commit b80a2cbdb677a8954f00f3394c2f8050ed511ad4 (HEAD, refs/remotes/origin/master) Author: Jared Finder Date: Sat May 18 20:51:09 2024 -0700 Fix byte compiler warnings in window-tool-bar.el * lisp/window-tool-bar.el (window-tool-bar--static-if) (window-tool-bar--ignored-event-types): Avoid byte compiler seeing variables obsolete in Emacs 30 and up. (Bug#68765) diff --git a/lisp/window-tool-bar.el b/lisp/window-tool-bar.el index 640deccdd61..395aa3aa9cc 100644 --- a/lisp/window-tool-bar.el +++ b/lisp/window-tool-bar.el @@ -335,15 +335,34 @@ MENU-ITEM is a menu item to convert. See info node (elisp)Tool Bar." (interactive) nil) +;; static-if was added in Emacs 30, but this packages supports earlier +;; versions. +(defmacro window-tool-bar--static-if (condition then-form &rest else-forms) + "A conditional compilation macro. +Evaluate CONDITION at macro-expansion time. If it is non-nil, +expand the macro to THEN-FORM. Otherwise expand it to ELSE-FORMS +enclosed in a `progn' form. ELSE-FORMS may be empty." + (declare (indent 2) + (debug (sexp sexp &rest sexp))) + (if (eval condition lexical-binding) + then-form + (cons 'progn else-forms))) + (defvar window-tool-bar--ignored-event-types - (let ((list (list 'mouse-movement 'pinch - 'wheel-down 'wheel-up 'wheel-left 'wheel-right + (let ((list (append + '(mouse-movement pinch + wheel-down wheel-up wheel-left wheel-right) + ;; Prior to emacs 30, wheel events could also surface as + ;; mouse- buttons. + (window-tool-bar--static-if (version< emacs-version "30") + (list mouse-wheel-down-event mouse-wheel-up-event mouse-wheel-left-event mouse-wheel-right-event (bound-and-true-p mouse-wheel-down-alternate-event) (bound-and-true-p mouse-wheel-up-alternate-event) (bound-and-true-p mouse-wheel-left-alternate-event) - (bound-and-true-p mouse-wheel-right-alternate-event)))) + (bound-and-true-p mouse-wheel-right-alternate-event)) + nil)))) (delete-dups (delete nil list))) "Cache for `window-tool-bar--last-command-triggers-refresh-p'.") commit 48563687f28b900c5d2044403c6576fbbc4cfa01 Author: Po Lu Date: Sun May 19 09:46:26 2024 +0800 Fix the DJGPP build * config.bat: Generate stdbit.in-h from stdbit.in.h. * msdos/sedlibmk.inp (GL_STDC_...): Enable generation of ISO C2x features. (STDBIT_H): Define to stdbit.h. (GL_GENERATE_STDBIT_H_CONDITION): Define to 1. diff --git a/config.bat b/config.bat index f63da88303c..20dbfda5548 100644 --- a/config.bat +++ b/config.bat @@ -303,6 +303,7 @@ If Exist sys_types.in.h update sys_types.in.h sys_types.in-h If Exist time.in.h update time.in.h time.in-h If Exist unistd.in.h update unistd.in.h unistd.in-h If Exist stdckdint.in.h update stdckdint.in.h stdckdint.in-h +If Exist stdbit.in.h update stdbit.in.h stdbit.in-h If Exist gnulib.mk.in update gnulib.mk.in gnulib.mk-in Rem Only repository has the msdos/autogen directory If Exist Makefile.in sed -f ../msdos/sedlibcf.inp < Makefile.in > makefile.tmp diff --git a/msdos/sedlibmk.inp b/msdos/sedlibmk.inp index a68e6f6aed3..d0b2da08656 100644 --- a/msdos/sedlibmk.inp +++ b/msdos/sedlibmk.inp @@ -198,6 +198,9 @@ s/@PACKAGE@/emacs/ # we get warnings building canonicalize-lgpl.o /^GL_GNULIB_RAWMEMCHR *=/s/@GL_GNULIB_RAWMEMCHR@/1/ /^GL_GNULIB_[^ =]* *= *@/s/@[^@\n]*@/0/ +# These variables control whether ISO C23 features are generated, +# e.g. those in stdbit.h. +/^GL_STDC_[^ =]* *= *@/s/@[^@\n]*@/1/ /^GL_GSETTINGS_CFLAGS *=/s/@[^@\n]*@// /^GL_GSETTINGS_LIBS *=/s/@[^@\n]*@// # Miscellaneous variables. @@ -347,6 +350,7 @@ s/@PACKAGE@/emacs/ /^LIMITS_H *=/s/@[^@\n]*@/limits.h/ /^IEEE754_H *=/s/@[^@\n]*@/ieee754.h/ /^STDALIGN_H *=/s/@[^@\n]*@/stdalign.h/ +/^STDBIT_H *=/s/@[^@\n]*@/stdbit.h/ /^STDCKDINT_H *=/s/@[^@\n]*@/stdckdint.h/ /^STDDEF_H *=/s/@[^@\n]*@/stddef.h/ /^STDDEF_NOT_IDEMPOTENT *=/s/@[^@\n]*@/1/ @@ -445,6 +449,7 @@ s/= @GL_GENERATE_GMP_H_CONDITION@/= 1/ s/= @GL_GENERATE_GMP_GMP_H_CONDITION@/= / s/= @GL_GENERATE_MINI_GMP_H_CONDITION@/= 1/ s/= @GL_GENERATE_STDCKDINT_H_CONDITION@/= 1/ +s/= @GL_GENERATE_STDBIT_H_CONDITION@/= 1/ s/= @GL_COND_OBJ_STDIO_READ_CONDITION@/= / s/= @GL_COND_OBJ_STDIO_WRITE_CONDITION@/= / s/= @GL_COND_OBJ_STPNCPY_CONDITION@/= / commit cf80d9831c62a8d0bfa98aec912862e7412a99c4 Author: Po Lu Date: Sun May 19 09:38:50 2024 +0800 Fix Android 2.2 build * src/android.h: Include sys/select.h. diff --git a/src/android.h b/src/android.h index 78482d64de4..29459b063f3 100644 --- a/src/android.h +++ b/src/android.h @@ -31,6 +31,8 @@ along with GNU Emacs. If not, see . */ #include #include +#include + #include #include commit 3c2c6ab733623433150b3bc82598c4bf2563ec87 Author: Po Lu Date: Sun May 19 09:16:59 2024 +0800 Fix Android build * src/androidfns.c: Include stdlib.h. diff --git a/src/androidfns.c b/src/androidfns.c index 1c2690394a6..4246f6d2be4 100644 --- a/src/androidfns.c +++ b/src/androidfns.c @@ -19,6 +19,7 @@ along with GNU Emacs. If not, see . */ #include #include +#include #include "lisp.h" #include "android.h" commit 9ec124e59ad3306a732749669f81aa4a870ce936 Author: Stefan Kangas Date: Sun May 19 01:10:50 2024 +0200 * lisp/play/doctor.el: Add a few more word meanings. diff --git a/lisp/play/doctor.el b/lisp/play/doctor.el index 4f18ae14f23..fa07fe3b09c 100644 --- a/lisp/play/doctor.el +++ b/lisp/play/doctor.el @@ -587,6 +587,8 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning vms 'mach) (doctor-put-meaning ibm 'mach) (doctor-put-meaning pc 'mach) +(doctor-put-meaning gnu 'mach) +(doctor-put-meaning linux 'mach) (doctor-put-meaning bitching 'foul) (doctor-put-meaning shit 'foul) (doctor-put-meaning bastard 'foul) @@ -624,6 +626,8 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning cocaine 'drug) (doctor-put-meaning uppers 'drug) (doctor-put-meaning downers 'drug) +(doctor-put-meaning opium 'drug) +(doctor-put-meaning valium 'drug) (doctor-put-meaning loves 'loves) (doctor-put-meaning love 'love) (doctor-put-meaning loved 'love) @@ -653,6 +657,8 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning likes 'desire) (doctor-put-meaning needs 'desire) (doctor-put-meaning need 'desire) +(doctor-put-meaning crave 'desire) +(doctor-put-meaning craves 'desires) (doctor-put-meaning frustrated 'mood) (doctor-put-meaning depressed 'mood) (doctor-put-meaning annoyed 'mood) @@ -670,6 +676,9 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning fear 'fear) (doctor-put-meaning scared 'fear) (doctor-put-meaning frightened 'fear) +(doctor-put-meaning panic 'fear) +(doctor-put-meaning phobia 'fear) +(doctor-put-meaning phobias 'fear) (doctor-put-meaning virginity 'sexnoun) (doctor-put-meaning virgins 'sexnoun) (doctor-put-meaning virgin 'sexnoun) @@ -699,6 +708,11 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning grandfather 'family) (doctor-put-meaning maternal 'family) (doctor-put-meaning paternal 'family) +(doctor-put-meaning cousin 'family) +(doctor-put-meaning aunt 'family) +(doctor-put-meaning uncle 'family) +(doctor-put-meaning niece 'family) +(doctor-put-meaning nephew 'family) (doctor-put-meaning stab 'death) (doctor-put-meaning murder 'death) (doctor-put-meaning murders 'death) @@ -728,6 +742,8 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning barf 'symptoms) (doctor-put-meaning toothache 'symptoms) (doctor-put-meaning hurt 'symptoms) +(doctor-put-meaning nausea 'symptoms) +(doctor-put-meaning cough 'symptoms) (doctor-put-meaning rum 'alcohol) (doctor-put-meaning gin 'alcohol) (doctor-put-meaning vodka 'alcohol) @@ -737,6 +753,8 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning wine 'alcohol) (doctor-put-meaning whiskey 'alcohol) (doctor-put-meaning scotch 'alcohol) +(doctor-put-meaning tequila 'alcohol) +(doctor-put-meaning martini 'alcohol) (doctor-put-meaning fuck 'sexverb) (doctor-put-meaning fucked 'sexverb) (doctor-put-meaning screw 'sexverb) @@ -778,6 +796,9 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning profs 'school) (doctor-put-meaning professors 'school) (doctor-put-meaning mit 'school) +(doctor-put-meaning university 'school) +(doctor-put-meaning college 'school) +(doctor-put-meaning homework 'school) (doctor-put-meaning emacs 'eliza) (doctor-put-meaning eliza 'eliza) (doctor-put-meaning liza 'eliza) @@ -815,6 +836,7 @@ reads the sentence before point, and prints the Doctor's answer." (doctor-put-meaning geometric 'math) (doctor-put-meaning calculus 'math) (doctor-put-meaning arithmetic 'math) +(doctor-put-meaning topology 'math) (doctor-put-meaning zippy 'zippy) (doctor-put-meaning zippy 'zippy) (doctor-put-meaning pinhead 'zippy) commit fee637468b5e72fd6fcd2c96c42622455db5fb16 Author: F. Jason Park Date: Wed May 8 19:03:58 2024 -0700 Reconcile erc-stamp--date-stamps when merging buffers * etc/ERC-NEWS: Mention new face `erc-information'. * lisp/erc/erc-button.el (erc-button-add-buttons): Skip buttonization when the "msg prop" `erc--skip' is present and contains the symbol `button'. Set `alist' to nil in the same guard condition as a roundabout way of suppressing further processing. * lisp/erc/erc-networks.el (erc--insert-admin-message): Forward declaration. (erc-networks--insert-transplanted-content) (erc-networks--transplant-buffer-content): Replace former with latter. Change signature to take source and destination buffers as parameters. (erc-networks--transplant-target-buffer-function): New function-valued variable. (erc-networks--target-transplant-in-progress-p): New variable, a flag for downstream code to detect when a transplant is underway. (erc-networks--reclaim-orphaned-target-buffers): Defer to `erc-networks--transplant-target-buffer-function' to handle the actual transplant business. Crucially, kill the buffer afterwards instead of beforehand. If new buffer-association bugs emerge related to the combining of old or renamed target buffers, this reordering may be at fault. (erc-networks--copy-over-server-buffer-contents): Pass old and new buffers to `erc-networks--insert-transplanted-content'. * lisp/erc/erc-stamp.el (erc-stamp--defer-date-insertion-on-post-modify): Set `fn' slot of `erc-stamp--date' instance to `ignore' when running the actual callback in order to conserve a little space. (erc-stamp--date-mode): Add and remove hook members for `erc-networks--copy-server-buffer-functions' and `erc-networks--transplant-target-buffer-function'. (erc-insert-timestamp-left-and-right): Always clear `erc-timestamp-last-inserted-right' to ensure a right stamp accompanies every date stamp. (erc-stamp--dedupe-date-stamps) (erc-stamp--dedupe-date-stamps-from-buffer) (erc-stamp--dedupe-date-stamps-from-target-buffer): New functions. Date stamp behavior was revamped as part of bug#60936. * lisp/erc/erc.el (erc-informational): New face. (erc--insert-admin-message): New function to hide some "msg prop" complexity from "upstream" libraries, like `erc-networks', and thus avoid more forward-declarations. A less smelly approach would be to devise a general interface owned by such libraries, or erc-common, that `erc-mode' could then hook into on init. (erc-display-message-highlight): Make face matching more limber to accommodate the convention of face names lacking a "-face" suffix. (erc-message-english-graft): New variable. (erc-kill-channel): Inhibit execution of hook when `erc-networks--target-transplant-in-progress-p' is non-nil. * test/lisp/erc/erc-networks-tests.el (erc-networks--rename-server-buffer--no-existing--orphan) (erc-networks--rename-server-buffer--existing--reuse) (erc-networks--rename-server-buffer--local-match) (erc-networks--rename-server-buffer--local-nomatch): Use helper to initialize markers. * test/lisp/erc/erc-stamp-tests.el (erc-stamp--dedupe-date-stamps): New test. (Bug#70928) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index 2c3c6c365a1..62970f52396 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -339,6 +339,13 @@ Also available as the library functions 'erc-cmd-AME', 'erc-cmd-GME', and 'erc-cmd-GMSG', these new slash commands can prove handy in test environments. +** New face 'erc-information' for local administrative messages. +Messages not originating from a server have historically been shown in +'erc-notice-face', sometimes in combination with 'erc-error-face'. +Neither are well suited for local messages of moderate importance. +From now on, such messages will appear in a more muted color but +retain the familiar 'erc-notice-prefix' stars. + ** Miscellaneous UX changes. Some minor quality-of-life niceties have finally made their way to ERC. For example, fool visibility has become togglable with the new diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el index 1f9d6fd64c0..8cf8991e57c 100644 --- a/lisp/erc/erc-button.el +++ b/lisp/erc/erc-button.el @@ -309,7 +309,9 @@ specified by `erc-button-alist'." regexp) (erc-button-remove-old-buttons) (unless (or erc-button--has-nickname-entry - (not erc-button-buttonize-nicks)) + (not erc-button-buttonize-nicks) + (and (erc--memq-msg-prop 'erc--skip 'button) + (not (setq alist nil)))) (erc-button-add-nickname-buttons `(_ _ erc-button--modify-nick-function ,erc-button-nickname-callback-function))) diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el index 1b26afa1164..a5ca05b137a 100644 --- a/lisp/erc/erc-networks.el +++ b/lisp/erc/erc-networks.el @@ -50,6 +50,7 @@ (defvar erc-server-process) (declare-function erc--get-isupport-entry "erc-backend" (key &optional single)) +(declare-function erc--insert-admin-message "erc" (&rest args)) (declare-function erc-buffer-filter "erc" (predicate &optional proc)) (declare-function erc-current-nick "erc" nil) (declare-function erc-display-error-notice "erc" (parsed string)) @@ -1345,24 +1346,38 @@ Copy source (prefix) from MOTD-ish message as a last resort." (setq erc-network nil) nil) -;; TODO add note in Commentary saying that this module is considered a -;; core module and that it's as much about buffer naming and network -;; identity as anything else. - -(defun erc-networks--insert-transplanted-content (content) - (let ((inhibit-read-only t) - (buffer-undo-list t)) - (save-excursion - (save-restriction - (widen) - (goto-char (point-min)) - (insert-before-markers content))))) +(defun erc-networks--transplant-buffer-content (src dest) + "Insert buffer SRC's contents into DEST, above its contents." + (with-silent-modifications + (let ((content (with-current-buffer src + (cl-assert (not (buffer-narrowed-p))) + (erc--insert-admin-message 'graft ?n dest ?o src) + (buffer-substring (point-min) erc-insert-marker)))) + (with-current-buffer dest + (save-excursion + (save-restriction + (cl-assert (not (buffer-narrowed-p))) + (goto-char (point-min)) + (while (and (eql ?\n (char-after (point))) + (null (text-properties-at (point)))) + (delete-char 1)) + (insert-before-markers content))))))) + +(defvar erc-networks--transplant-target-buffer-function + #'erc-networks--transplant-buffer-content + "Function to rename and merge the contents of two target buffers. +Called with the donating buffer to be killed and buffer to receive the +transplant. Consuming modules can leave a marker at the beginning of +the latter buffer to access the insertion point, if needing to do things +like adjust invisibility properties, etc.") + +(defvar erc-networks--target-transplant-in-progress-p nil + "Non-nil when merging target buffers.") ;; This should run whenever a network identity is updated. - (defun erc-networks--reclaim-orphaned-target-buffers (new-proc nid announced) "Visit disowned buffers for same NID and associate with NEW-PROC. -ANNOUNCED is the server's reported host name." +Expect ANNOUNCED to be the server's reported host name." (erc-buffer-filter (lambda () (when (and erc--target @@ -1372,20 +1387,26 @@ ANNOUNCED is the server's reported host name." (string= erc-server-announced-name announced))) ;; If a target buffer exists for the current process, kill this ;; stale one after transplanting its content; else reinstate. - (if-let ((existing (erc-get-buffer - (erc--target-string erc--target) new-proc))) + (if-let ((actual (erc-get-buffer (erc--target-string erc--target) + new-proc)) + (erc-networks--target-transplant-in-progress-p t)) (progn - (widen) - (let ((content (buffer-substring (point-min) - erc-insert-marker))) - (kill-buffer) ; allow target-buf renaming hook to run - (with-current-buffer existing - (erc-networks--ensure-unique-target-buffer-name) - (erc-networks--insert-transplanted-content content)))) + (funcall erc-networks--transplant-target-buffer-function + (current-buffer) actual) + (kill-buffer (current-buffer)) + (with-current-buffer actual + (erc-networks--ensure-unique-target-buffer-name))) (setq erc-server-process new-proc erc-server-connected t erc-networks--id nid)))))) +;; For existing buffers, `erc-open' reinitializes a core set of local +;; variables in addition to some text, such as the prompt. It expects +;; module activation functions to do the same for assets they manage. +;; However, "stateful" modules, whose functionality depends on the +;; evolution of a buffer's content, may need to reconcile state during +;; a merge. An example might be a module that provides consistent +;; timestamps: it should ensure time values don't decrease. (defvar erc-networks--copy-server-buffer-functions nil "Abnormal hook run in new server buffers when deduping. Passed the existing buffer to be killed, whose contents have @@ -1393,26 +1414,18 @@ already been copied over to the current, replacement buffer.") (defun erc-networks--copy-over-server-buffer-contents (existing name) "Kill off existing server buffer after copying its contents. -Must be called from the replacement buffer." +Expect to be called from the replacement buffer." (defvar erc-kill-buffer-hook) (defvar erc-kill-server-hook) - ;; ERC expects `erc-open' to be idempotent when setting up local - ;; vars and other context properties for a new identity. Thus, it's - ;; unlikely we'll have to copy anything else over besides text. And - ;; no reconciling of user tables, etc. happens during a normal - ;; reconnect, so we should be fine just sticking to text. (Right?) - (let ((text (with-current-buffer existing - ;; This `erc-networks--id' should be - ;; `erc-networks--id-equal-p' to caller's network - ;; identity and older if not eq. - ;; - ;; `erc-server-process' should be set but dead - ;; and eq `get-buffer-process' unless latter nil - (delete-process erc-server-process) - (buffer-substring (point-min) erc-insert-marker))) - erc-kill-server-hook - erc-kill-buffer-hook) - (erc-networks--insert-transplanted-content text) + ;; The following observations from ERC 5.5 regarding the buffer + ;; `existing' were thought at the time to be invariants: + ;; - `erc-networks--id' is `erc-networks--id-equal-p' to the + ;; caller's network identity and older if not `eq'. + ;; - `erc-server-process' should be set (local) but dead and `eq' to + ;; the result of `get-buffer-process' unless the latter is nil. + (delete-process (buffer-local-value 'erc-server-process existing)) + (erc-networks--transplant-buffer-content existing (current-buffer)) + (let (erc-kill-server-hook erc-kill-buffer-hook) (run-hook-with-args 'erc-networks--copy-server-buffer-functions existing) (kill-buffer name))) diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el index fd137c0548a..a9ffdb18ba7 100644 --- a/lisp/erc/erc-stamp.el +++ b/lisp/erc/erc-stamp.el @@ -730,6 +730,7 @@ non-nil." (fset symbol (lambda (&rest _) (remove-hook hook-var symbol) + (setf (erc-stamp--date-fn data) #'ignore) (when (buffer-live-p buffer) (with-current-buffer buffer (setq erc-stamp--date-stamps @@ -773,11 +774,20 @@ non-nil." :interactive nil (if erc-stamp--date-mode (progn + (add-function :around + (local 'erc-networks--transplant-target-buffer-function) + #'erc-stamp--dedupe-date-stamps-from-target-buffer) + (add-hook 'erc-networks--copy-server-buffer-functions + #'erc-stamp--dedupe-date-stamps-from-buffer 0 t) (add-hook 'erc-insert-post-hook #'erc-stamp--defer-date-insertion-on-post-insert 0 t) (add-hook 'erc-send-post-hook #'erc-stamp--defer-date-insertion-on-post-send 0 t)) (kill-local-variable 'erc-timestamp-last-inserted-left) + (remove-function (local 'erc-networks--transplant-target-buffer-function) + #'erc-stamp--dedupe-date-stamps-from-target-buffer) + (remove-hook 'erc-networks--copy-server-buffer-functions + #'erc-stamp--dedupe-date-stamps-from-buffer t) (remove-hook 'erc-insert-post-hook #'erc-stamp--defer-date-insertion-on-post-insert t) (remove-hook 'erc-send-post-hook @@ -841,6 +851,8 @@ and date stamps inserted by this function." ((not (string-equal rendered erc-timestamp-last-inserted-left))) ((null (cl-find rendered erc-stamp--date-stamps :test #'string= :key #'erc-stamp--date-str)))) + ;; Force `erc-insert-timestamp-right' to stamp this message. + (setq erc-timestamp-last-inserted-right nil) (setq erc-stamp--deferred-date-stamp (make-erc-stamp--date :ts ct :str rendered)))) ;; insert right timestamp @@ -1040,6 +1052,47 @@ And discard stale references in `erc-stamp--date-stamps'." erc-timestamp-last-inserted-left nil erc-timestamp-last-inserted-right nil))) +(defun erc-stamp--dedupe-date-stamps (old-stamps) + "Update `erc-stamp--date-stamps' from its counterpart OLD-STAMPS. +Assume the contents of the buffer for OLD-STAMPS have just been inserted +above the current buffer's and that the old buffer still exists so that +markers still point somewhere. For each duplicate, update the existing +marker to match the transplanted timestamp with the same date. Also +copy non-duplicate `erc-stamp--date' objects from OLD-STAMPS to the +current buffer's, maintaining order." + (let (need) + (dolist (old old-stamps) + (if-let ((new (cl-find (erc-stamp--date-str old) erc-stamp--date-stamps + :test #'string= :key #'erc-stamp--date-str)) + (new-marker (erc-stamp--date-marker new))) + ;; The new buffer now has a duplicate stamp, so remove the + ;; "newer" one from the buffer. + (progn + (erc--delete-inserted-message-naively new-marker) + (set-marker new-marker (erc-stamp--date-marker old))) + ;; The new buffer doesn't have this stamp, so add its data + ;; object to the sorted list. + (push old need) + ;; Update the old marker position to point to the new buffer. + (set-marker (erc-stamp--date-marker old) + (erc-stamp--date-marker old)))) + ;; These *should* already be sorted. + (setq erc-stamp--date-stamps + (nconc (nreverse need) erc-stamp--date-stamps)))) + +(defun erc-stamp--dedupe-date-stamps-from-buffer (old-buffer) + "Merge date stamps from OLD-BUFFER into in the current buffer." + (let ((old-stamps (buffer-local-value 'erc-stamp--date-stamps old-buffer))) + (erc-stamp--dedupe-date-stamps old-stamps))) + +(defun erc-stamp--dedupe-date-stamps-from-target-buffer (orig old-buffer + new-buffer) + "Merge date stamps from OLD-BUFFER into NEW-BUFFER after calling ORIG." + (let ((old-stamps (buffer-local-value 'erc-stamp--date-stamps old-buffer))) + (prog1 (funcall orig old-buffer new-buffer) + (with-current-buffer new-buffer + (erc-stamp--dedupe-date-stamps old-stamps))))) + (provide 'erc-stamp) ;;; erc-stamp.el ends here diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 5aa6be5e553..9100ab5577d 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -1521,6 +1521,10 @@ This will only be used if `erc-header-line-face-method' is non-nil." "ERC face for errors." :group 'erc-faces) +(defface erc-information '((t :inherit shadow)) + "Face for local administrative messages of low to moderate importance." + :group 'erc-faces) + ;; same default color as `erc-input-face' (defface erc-my-nick-face '((t :weight bold :foreground "brown")) "ERC face for your current nickname in messages sent by you. @@ -3526,6 +3530,14 @@ being equivalent to a `erc-display-message' TYPE of `notice'." (push '(erc--msg . notice) erc--msg-prop-overrides))) (erc-display-message nil nil buffer string))) +(defun erc--insert-admin-message (msg &rest args) + "Print MSG with ARGS as a local notice. +Inhibit all stamps and buttonizing." + (let ((erc--msg-prop-overrides `((erc--skip . (stamp track button)) + ,@erc--msg-prop-overrides))) + (apply #'erc-display-message nil '(notice information) + (current-buffer) msg args))) + (defvar erc--merge-text-properties-p nil "Non-nil when `erc-put-text-property' defers to `erc--merge-prop'.") @@ -3732,9 +3744,12 @@ See also `erc-make-notice'." (t (erc-put-text-property 0 (length string) - 'font-lock-face (or (intern-soft - (concat "erc-" (symbol-name type) "-face")) - 'erc-default-face) + 'font-lock-face + (let* ((name (symbol-name type)) + (symbol (or (intern-soft (concat "erc-" name "-face")) + (intern-soft (concat "erc-" name)) + type))) + (or (and (facep symbol) symbol) 'erc-default-face)) string) string))) @@ -9434,6 +9449,7 @@ SOFTP, only do so when defined as a variable." (finished . "\n\n*** ERC finished ***\n") (terminated . "\n\n*** ERC terminated: %e\n") (login . "Logging in as `%n'...") + (graft . "Grafting buffer `%n' onto `%o'...") ; {new} onto {old} (nick-in-use . "%n is in use. Choose new nickname: ") (nick-too-long . "WARNING: Nick length (%i) exceeds max NICKLEN(%l) defined by server") @@ -9672,6 +9688,7 @@ This function should be on `erc-kill-server-hook'." (defun erc-part-channel-on-kill () "Send a \"PART\" when killing a channel buffer." (when (and (not erc-killing-buffer-on-part-p) + (not erc-networks--target-transplant-in-progress-p) (erc-server-process-alive)) (let ((tgt (erc-default-target))) (if tgt diff --git a/test/lisp/erc/erc-networks-tests.el b/test/lisp/erc/erc-networks-tests.el index 0d8861f2167..90d6f13f2f6 100644 --- a/test/lisp/erc/erc-networks-tests.el +++ b/test/lisp/erc/erc-networks-tests.el @@ -1243,6 +1243,7 @@ (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-process (erc-networks-tests--create-live-proc) @@ -1282,6 +1283,7 @@ (ert-info ("New buffer steals name, content") (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-process (erc-networks-tests--create-live-proc) @@ -1522,6 +1524,7 @@ (ert-info ("New server buffer steals name, content") (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-announced-name "us-east.foonet.org" @@ -1574,6 +1577,7 @@ (ert-info ("New server buffer steals name, content") (with-current-buffer (get-buffer-create "irc.foonet.org") (erc-mode) + (erc--initialize-markers (point) nil) (setq erc-network 'FooNet erc-server-current-nick "tester" erc-server-announced-name "us-east.foonet.org" ; east diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el index 5fee21ec28f..61f03685e5d 100644 --- a/test/lisp/erc/erc-stamp-tests.el +++ b/test/lisp/erc/erc-stamp-tests.el @@ -349,4 +349,122 @@ (lambda (arg) (should (equal '(3 . 19) (erc--get-inserted-msg-bounds arg)))))) +(ert-deftest erc-stamp--dedupe-date-stamps-from-target-buffer () + (unless (>= emacs-major-version 29) + (ert-skip "Requires hz-ticks lisp time format")) + (let ((erc-modules erc-modules) + (erc-stamp--tz t)) + (erc-tests-common-make-server-buf) + (erc-stamp-mode +1) + + ;; Create two buffers with an overlapping date stamp. + (with-current-buffer (erc--open-target "#chan@old") + (let ((erc-stamp--current-time '(1690761600001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-07-31T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1690761601001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "0.0")) + + (let ((erc-stamp--current-time '(1690848000001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-01T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1690848001001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "1.0")) + (let ((erc-stamp--current-time '(1690848060001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "1.1")) + + (let ((erc-stamp--current-time '(1690934400001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-02T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1690934401001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "2.0")) + (let ((erc-stamp--current-time '(1690956000001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "2.6"))) + + (with-current-buffer (erc--open-target "#chan@new") + (let ((erc-stamp--current-time '(1690956001001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-02T06:00:01.001Z")) + (let ((erc-stamp--current-time '(1690963200001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "2.8")) + + (let ((erc-stamp--current-time '(1691020800001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-03T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1691020801001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "3.0")) + (let ((erc-stamp--current-time '(1691053200001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "3.9")) + + (let ((erc-stamp--current-time '(1691107200001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) + "2023-08-04T00:00:00.001Z")) + (let ((erc-stamp--current-time '(1691107201001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "4.0")) + (let ((erc-stamp--current-time '(1691110800001 . 1000))) + (erc-tests-common-display-message nil 'notice (current-buffer) "4.1"))) + + (erc-stamp--dedupe-date-stamps-from-target-buffer + #'erc-networks--transplant-buffer-content + (get-buffer "#chan@old") + (get-buffer "#chan@new")) + + ;; Ensure the "model", `erc-stamp--date-stamps', matches reality + ;; in the buffer's contents. + (with-current-buffer "#chan@new" + (let ((stamps erc-stamp--date-stamps)) + (goto-char 3) + (should (looking-at (rx "\n[Mon Jul 31 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-07-31T00:00:00.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 0.0"))) + (forward-line 1) + + (should (looking-at (rx "\n[Tue Aug 1 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-08-01T00:00:00.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 1.0"))) + (forward-line 1) + (should (looking-at (rx "*** 1.1"))) + (forward-line 1) + + (should (looking-at (rx "\n[Wed Aug 2 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-08-02T00:00:00.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 2.0"))) + (forward-line 1) + (should (looking-at (rx "*** 2.6"))) + (forward-line 1) + (should (looking-at + (rx "*** Grafting buffer `#chan@new' onto `#chan@old'"))) + (forward-line 1) + (should (looking-at (rx "*** 2023-08-02T06:00:01.001Z"))) + (forward-line 1) + (should (looking-at (rx "*** 2.8"))) + (forward-line 1) + + (should (looking-at (rx "\n[Thu Aug 3 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (goto-char (1+ (match-end 0))) + (should (looking-at (rx "*** 2023-08-03T00:00:00.001Z"))) + (forward-line 3) ; ... + + (should (looking-at (rx "\n[Fri Aug 4 2023]"))) + (should (= (erc--get-inserted-msg-beg (point)) + (erc-stamp--date-marker (pop stamps)))) + (should-not stamps)))) + + (when noninteractive + (erc-tests-common-kill-buffers))) + ;;; erc-stamp-tests.el ends here commit cf7cc4c630a2cd71c52069237053cb1476104572 Author: F. Jason Park Date: Tue May 14 21:09:55 2024 -0700 Don't kill server buffer with erc-kill-buffer-on-part * etc/ERC-NEWS: Mention new flag `erc-killing-buffer-on-part-p' and the renaming of `erc-kill-channel'. * lisp/erc/erc-backend.el (erc-server-PART): Only kill a buffer on behalf of `erc-kill-buffer-on-part' when the buffer hasn't already been killed, and bind `erc-killing-buffer-on-part-p' to t when doing so. * lisp/erc/erc-log.el (erc-conditional-save-buffer): Don't save logs when the buffer parameter is nil because that causes the server buffer to be saved out. It's possible that user code relying on this longstanding bug will be affected, however, by default, the server buffer will also be saved out independently at designated junctures. * lisp/erc/erc.el (erc-part-hook): Redo doc string. (erc-killing-buffer-on-part-p): New variable, a flag to prevent redundant execution of `erc-kill-channel-hook' members concerned with parted channels. (erc-kill-buffer-on-part): Tweak doc string. (erc-kill-channel-hook): Use new name for `erc-kill-channel', `erc-part-channel-on-kill'. (erc-kill-channel, erc-part-channel-on-kill): Rename former to latter, and inhibit execution when `erc-killing-buffer-on-part-p' is non-nil. * test/lisp/erc/erc-scenarios-base-kill-on-part.el: New file. (Bug#70840) diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS index b66ea6a7a02..2c3c6c365a1 100644 --- a/etc/ERC-NEWS +++ b/etc/ERC-NEWS @@ -648,6 +648,14 @@ release lacks a similar solution for detecting "joinedness" directly, but users can turn to 'xor'-ing 'erc-default-target' and 'erc-target' as a makeshift kludge. +*** Function 'erc-kill-channel' renamed to 'erc-part-channel-on-kill'. +This function, which normally emits a 'PART' when ERC kills a channel +buffer, has been renamed for clarity. Moreover, this and all other +members of 'erc-kill-channel-hook' can now take comfort in knowing +that the killing of buffers done on behalf of the option +'erc-kill-buffer-on-part' has been made more detectable by the flag +'erc-killing-buffer-on-part-p'. + *** Channel-mode handling has become stricter and more predictable. ERC has always processed channel modes using "standardized" letters and popular status prefixes. Starting with this release, ERC will diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el index ab419d2b018..ef99d762a07 100644 --- a/lisp/erc/erc-backend.el +++ b/lisp/erc/erc-backend.el @@ -1883,6 +1883,9 @@ add things to `%s' instead." (buffer (erc-get-buffer chnl proc))) (pcase-let ((`(,nick ,login ,host) (erc-parse-user (erc-response.sender parsed)))) + ;; When `buffer' is nil, `erc-remove-channel-member' and + ;; `erc-remove-channel-users' do almost nothing, and the message + ;; is displayed in the server buffer. (erc-remove-channel-member buffer nick) (erc-display-message parsed 'notice buffer 'PART ?n nick ?u login @@ -1896,8 +1899,10 @@ add things to `%s' instead." (erc-delete-default-channel chnl buffer)) (erc-update-mode-line buffer) (defvar erc-kill-buffer-on-part) - (when erc-kill-buffer-on-part - (kill-buffer buffer)))))) + (when (and erc-kill-buffer-on-part buffer) + (defvar erc-killing-buffer-on-part-p) + (let ((erc-killing-buffer-on-part-p t)) + (kill-buffer buffer))))))) (define-erc-response-handler (PING) "Handle ping messages." nil diff --git a/lisp/erc/erc-log.el b/lisp/erc/erc-log.el index d5c56bcc2b3..66420662c23 100644 --- a/lisp/erc/erc-log.el +++ b/lisp/erc/erc-log.el @@ -289,8 +289,8 @@ Return nil if BUFFER is a server buffer." (erc-save-buffer-in-logs))) (defun erc-conditional-save-buffer (buffer) - "Save Query BUFFER if `erc-save-queries-on-quit' is t." - (when erc-save-buffer-on-part + "Save channel BUFFER if it and `erc-save-buffer-on-part' are non-nil." + (when (and buffer erc-save-buffer-on-part) (erc-save-buffer-in-logs buffer))) (defun erc-conditional-save-queries (process) diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index c92fd42322a..5aa6be5e553 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -470,13 +470,22 @@ See also `erc-server-QUIT-functions' and `erc-disconnected-hook'." (defcustom erc-part-hook nil "Hook run when processing a PART message directed at our nick. - -The hook receives one argument, the current BUFFER. -See also `erc-server-QUIT-functions', `erc-quit-hook' and -`erc-disconnected-hook'." +Called in the server buffer with a single argument: the channel buffer +being parted. For historical reasons, the buffer argument may be nil if +it's been killed or otherwise can't be found. This typically happens +when the \"PART\" response being handled comes by way of a channel +buffer being killed, which, by default, tells `erc-part-channel-on-kill' +to emit a \"PART\". Users needing to operate on a parted channel buffer +before it's killed in this manner should use `erc-kill-channel-hook' and +condition their code on `erc-killing-buffer-on-part-p' being nil." :group 'erc-hooks :type 'hook) +(defvar erc-killing-buffer-on-part-p nil + "Non-nil when killing a target buffer while handling a \"PART\" response. +Useful for preventing the redundant execution of code designed to run +once when parting a channel.") + (defcustom erc-kick-hook nil "Hook run when processing a KICK message directed at our nick. @@ -1114,8 +1123,7 @@ directory in the list." (defcustom erc-kill-buffer-on-part nil "Kill the channel buffer on PART. -This variable should probably stay nil, as ERC can reuse buffers if -you rejoin them later." +Nil by default because ERC can reuse buffers later re-joined." :group 'erc-quit-and-part :type 'boolean) @@ -9598,7 +9606,7 @@ See also `format-spec'." :type 'hook) (defcustom erc-kill-channel-hook - '(erc-kill-channel + '(erc-part-channel-on-kill erc-networks-shrink-ids-and-buffer-names erc-networks-rename-surviving-target-buffer) "Invoked whenever a channel-buffer is killed via `kill-buffer'." @@ -9659,10 +9667,12 @@ This function should be on `erc-kill-server-hook'." (setq erc-server-quitting t) (erc-server-send (format "QUIT :%s" (funcall erc-quit-reason nil))))) -(defun erc-kill-channel () - "Sends a PART command to the server when the channel buffer is killed. -This function should be on `erc-kill-channel-hook'." - (when (erc-server-process-alive) +(define-obsolete-function-alias 'erc-kill-channel #'erc-part-channel-on-kill + "30.1") +(defun erc-part-channel-on-kill () + "Send a \"PART\" when killing a channel buffer." + (when (and (not erc-killing-buffer-on-part-p) + (erc-server-process-alive)) (let ((tgt (erc-default-target))) (if tgt (erc-server-send (format "PART %s :%s" tgt diff --git a/test/lisp/erc/erc-scenarios-base-kill-on-part.el b/test/lisp/erc/erc-scenarios-base-kill-on-part.el new file mode 100644 index 00000000000..0ca0b1ae054 --- /dev/null +++ b/test/lisp/erc/erc-scenarios-base-kill-on-part.el @@ -0,0 +1,95 @@ +;;; erc-scenarios-base-kill-on-part.el --- killing buffers on part -*- lexical-binding: t -*- + +;; Copyright (C) 2024 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; 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 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Code: + +(require 'ert-x) +(eval-and-compile + (let ((load-path (cons (ert-resource-directory) load-path))) + (require 'erc-scenarios-common))) + +;; Assert channel buffer is killed when `erc-kill-buffer-on-part' is +;; enabled and a user issues a /part. Also assert that code in +;; `erc-kill-channel-hook' can detect when `erc-response-PART' is +;; killing a buffer on behalf of that option. +(ert-deftest erc-scenarios-base-kill-on-part--enabled () + :tags '(:expensive-test) + (should-not erc-kill-buffer-on-part) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/reuse-buffers/channel") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'foonet)) + (port (process-contact dumb-server :service)) + (erc-kill-buffer-on-part t) + (calls nil) + (erc-part-hook (lambda (b) (push (buffer-name b) calls))) + (erc-kill-channel-hook + (cons (lambda () (push erc-killing-buffer-on-part-p calls)) + erc-kill-channel-hook)) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "foonet:changeme" + :full-name "tester") + (funcall expect 10 "This server is in debug mode"))) + + (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#chan")) + (funcall expect 10 " bob: Whilst I can shake") + (erc-scenarios-common-say "/part")) + + (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) + (should (equal calls '(t "#chan"))))) + +;; When `erc-kill-buffer-on-part' is non-nil, and the parted buffer has +;; already been killed, don't kill the server buffer. Bug#70840 +(ert-deftest erc-scenarios-base-kill-on-part--enabled/killed () + :tags '(:expensive-test) + (should-not erc-kill-buffer-on-part) + + (erc-scenarios-common-with-cleanup + ((erc-scenarios-common-dialog "base/reuse-buffers/channel") + (erc-server-flood-penalty 0.1) + (dumb-server (erc-d-run "localhost" t 'foonet)) + (port (process-contact dumb-server :service)) + (erc-kill-buffer-on-part t) + (calls nil) + (erc-part-hook (lambda (b) (push b calls))) + (expect (erc-d-t-make-expecter))) + + (ert-info ("Connect to foonet") + (with-current-buffer (erc :server "127.0.0.1" + :port port + :nick "tester" + :password "foonet:changeme" + :full-name "tester") + (funcall expect 10 "This server is in debug mode"))) + + (with-current-buffer (erc-d-t-wait-for 20 (get-buffer "#chan")) + (funcall expect 10 " bob: Whilst I can shake") + (kill-buffer)) + + (erc-d-t-wait-for 20 (null (get-buffer "#chan"))) + (erc-d-t-wait-for 10 (equal calls '(nil))) + (erc-d-t-ensure-for 0.1 (get-buffer "foonet")))) + +;;; erc-scenarios-base-kill-on-part.el ends here commit e8feb04cc68f24d60d12390cef28064727d75669 Author: Augusto Stoffel Date: Wed Apr 24 18:13:36 2024 +0200 comint.el: Add applicable modes to 'interactive' forms * lisp/comint.el (comint-dynamic-list-input-ring-select) (comint-dynamic-list-input-ring, comint-restore-input) (comint-previous-input, comint-next-input) (comint-previous-matching-input, comint-next-matching-input) (comint-previous-matching-input-from-input) (comint-next-matching-input-from-input) (comint-replace-by-expanded-history, comint-magic-space) (comint-history-isearch-backward) (comint-history-isearch-backward-regexp, comint-send-input) (comint-truncate-buffer, comint-strip-ctrl-m) (comint-show-maximum-output, comint-copy-old-input, comint-bol) (comint-send-invisible, comint-delete-output, comint-write-output) (comint-append-output-to-file, comint-show-output) (comint-clear-buffer, comint-interrupt-subjob, comint-kill-subjob) (comint-quit-subjob, comint-stop-subjob, comint-continue-subjob) (comint-kill-input, comint-delchar-or-maybe-eof, comint-send-eof) (comint-backward-matching-input, comint-forward-matching-input) (comint-next-prompt, comint-previous-prompt) (comint-insert-previous-argument, comint-kill-whole-line) (comint-kill-region, comint-dynamic-complete-filename) (comint-replace-by-expanded-filename) (comint-dynamic-list-filename-completions) (comint-get-next-from-history, comint-accumulate) (comint-goto-process-mark, comint-bol-or-process-mark) (comint-set-process-mark, comint-redirect-cleanup) (comint-redirect-send-command) (comint-redirect-send-command-to-process, comint-fontify-input-mode): Add mode to interactive form. (Bug#70555) diff --git a/lisp/comint.el b/lisp/comint.el index e856038b0f7..3804932e01c 100644 --- a/lisp/comint.el +++ b/lisp/comint.el @@ -1122,7 +1122,7 @@ See also `comint-read-input-ring'." (defun comint-dynamic-list-input-ring-select () "Choose the input history entry that point is in or next to." - (interactive) + (interactive nil completion-list-mode) (let ((buffer completion-reference-buffer) beg end completion) (if (and (not (eobp)) (get-text-property (point) 'mouse-face)) @@ -1139,7 +1139,7 @@ See also `comint-read-input-ring'." (defun comint-dynamic-list-input-ring () "Display a list of recent inputs entered into the current buffer." - (interactive) + (interactive nil comint-mode) (if (or (not (ring-p comint-input-ring)) (ring-empty-p comint-input-ring)) (message "No history") @@ -1203,7 +1203,7 @@ See also `comint-read-input-ring'." (defun comint-restore-input () "Restore unfinished input." - (interactive) + (interactive nil comint) (when comint-input-ring-index (comint-delete-input) (when (> (length comint-stored-incomplete-input) 0) @@ -1232,7 +1232,7 @@ Moves relative to `comint-input-ring-index'." (defun comint-previous-input (arg) "Cycle backwards through input history, saving input." - (interactive "*p") + (interactive "*p" comint-mode) (if (and comint-input-ring-index (or ;; leaving the "end" of the ring (and (< arg 0) ; going down @@ -1246,7 +1246,7 @@ Moves relative to `comint-input-ring-index'." (defun comint-next-input (arg) "Cycle forwards through input history." - (interactive "*p") + (interactive "*p" comint-mode) (comint-previous-input (- arg))) (defun comint-previous-matching-input-string (regexp arg) @@ -1295,7 +1295,7 @@ Moves relative to START, or `comint-input-ring-index'." \(Previous history elements are earlier commands.) With prefix argument N, search for Nth previous match. If N is negative, find the next or Nth next match." - (interactive (comint-regexp-arg "Previous input matching (regexp): ")) + (interactive (comint-regexp-arg "Previous input matching (regexp): ") comint-mode) (setq n (comint-search-arg n)) (let ((pos (comint-previous-matching-input-string-position regexp n))) ;; Has a match been found? @@ -1325,7 +1325,7 @@ If N is negative, find the next or Nth next match." \(Later history elements are more recent commands.) With prefix argument N, search for Nth following match. If N is negative, find the previous or Nth previous match." - (interactive (comint-regexp-arg "Next input matching (regexp): ")) + (interactive (comint-regexp-arg "Next input matching (regexp): ") comint-mode) (comint-previous-matching-input regexp (- n))) (defun comint-previous-matching-input-from-input (n) @@ -1333,7 +1333,7 @@ If N is negative, find the previous or Nth previous match." \(Previous history elements are earlier commands.) With prefix argument N, search for Nth previous match. If N is negative, search forwards for the -Nth following match." - (interactive "p") + (interactive "p" comint-mode) (let ((opoint (point))) (unless (memq last-command '(comint-previous-matching-input-from-input comint-next-matching-input-from-input)) @@ -1355,7 +1355,7 @@ If N is negative, search forwards for the -Nth following match." \(Following history elements are more recent commands.) With prefix argument N, search for Nth following match. If N is negative, search backwards for the -Nth previous match." - (interactive "p") + (interactive "p" comint-mode) (comint-previous-matching-input-from-input (- n))) @@ -1380,7 +1380,7 @@ than the logical beginning of line. See `comint-magic-space' and `comint-replace-by-expanded-history-before-point'. Returns t if successful." - (interactive) + (interactive nil comint-mode) (let ((f (comint-c-a-p-replace-by-expanded-history silent start))) (if f (funcall f)))) @@ -1510,7 +1510,7 @@ actual side-effect." (defun comint-magic-space (arg) "Expand input history references before point and insert ARG spaces. A useful command to bind to SPC. See `comint-replace-by-expanded-history'." - (interactive "p") + (interactive "p" comint-mode) (comint-replace-by-expanded-history) (self-insert-command arg)) @@ -1532,13 +1532,13 @@ If nil, Isearch operates on the whole comint buffer." (defun comint-history-isearch-backward () "Search for a string backward in input history using Isearch." - (interactive) + (interactive nil comint-mode) (setq comint-history-isearch t) (isearch-backward nil t)) (defun comint-history-isearch-backward-regexp () "Search for a regular expression backward in input history using Isearch." - (interactive) + (interactive nil comint-mode) (setq comint-history-isearch t) (isearch-backward-regexp nil t)) @@ -1927,7 +1927,7 @@ If the Comint is Lucid Common Lisp, which matches (1) all whitespace (2) :a, :c, etc. Similarly for Soar, Scheme, etc." - (interactive) + (interactive nil comint-mode) ;; If we're currently completing, stop. We're definitely done ;; completing, and by sending the input, we might cause side effects ;; that will confuse the code running in the completion @@ -2376,7 +2376,7 @@ SELECTED is the window that was originally selected." (defun comint-truncate-buffer (&optional _string) "Truncate the buffer to `comint-buffer-maximum-size'. This function could be on `comint-output-filter-functions' or bound to a key." - (interactive) + (interactive nil comint-mode) (save-excursion (goto-char (process-mark (get-buffer-process (current-buffer)))) (forward-line (- comint-buffer-maximum-size)) @@ -2387,7 +2387,7 @@ This function could be on `comint-output-filter-functions' or bound to a key." (defun comint-strip-ctrl-m (&optional _string interactive) "Strip trailing `^M' characters from the current output group. This function could be on `comint-output-filter-functions' or bound to a key." - (interactive (list nil t)) + (interactive (list nil t) comint-mode) (let ((process (get-buffer-process (current-buffer)))) (if (not process) ;; This function may be used in @@ -2409,7 +2409,7 @@ This function could be on `comint-output-filter-functions' or bound to a key." (defun comint-show-maximum-output () "Put the end of the buffer at the bottom of the window." - (interactive) + (interactive nil comint-mode) (goto-char (point-max)) (recenter (- -1 scroll-margin))) @@ -2437,7 +2437,7 @@ the current line with any initial string matching the regexp (defun comint-copy-old-input () "Insert after prompt old input at point as new input to be edited. Calls `comint-get-old-input' to get old input." - (interactive) + (interactive nil comint-mode) (let ((input (funcall comint-get-old-input)) (process (get-buffer-process (current-buffer)))) (if (not process) @@ -2503,7 +2503,7 @@ If prefix argument is given (\\[universal-argument]) the prompt is not skipped. If `comint-use-prompt-regexp' is non-nil, then the prompt skip is done by skipping text matching the regular expression `comint-prompt-regexp', a buffer local variable." - (interactive "P") + (interactive "P" comint-mode) (if arg ;; Unlike `beginning-of-line', forward-line ignores field boundaries (forward-line 0) @@ -2530,7 +2530,7 @@ Then send it to the process running in the current buffer. The string is sent using `comint-input-sender'. Security bug: your string can still be temporarily recovered with \\[view-lossage]; `clear-this-command-keys' can fix that." - (interactive "P") ; Defeat snooping via C-x ESC ESC + (interactive "P" comint-mode) ; Defeat snooping via C-x ESC ESC (let ((proc (get-buffer-process (current-buffer))) (prefix (if (eq (window-buffer) (current-buffer)) @@ -2612,7 +2612,7 @@ If KILL (interactively, the prefix), save the killed text in the kill ring. This command does not delete the prompt." - (interactive "P") + (interactive "P" comint-mode) (let ((proc (get-buffer-process (current-buffer))) (replacement nil) (inhibit-read-only t)) @@ -2650,7 +2650,8 @@ otherwise." "Append output to file: " "Write output to file: ")) current-prefix-arg - (not current-prefix-arg))) + (not current-prefix-arg)) + comint-mode) (save-excursion (goto-char (process-mark (get-buffer-process (current-buffer)))) (forward-line 0) @@ -2662,13 +2663,13 @@ otherwise." (defun comint-append-output-to-file (filename) "Append output from interpreter since last input to FILENAME. Any prompt at the end of the output is not written." - (interactive "fAppend output to file: ") + (interactive "fAppend output to file: " comint-mode) (comint-write-output filename t)) (defun comint-show-output () "Display start of this batch of interpreter output at top of window. Sets mark to the value of point when this command is run." - (interactive) + (interactive nil comint-mode) (push-mark) (let ((pos (or (marker-position comint-last-input-end) (point-max)))) (cond (comint-use-prompt-regexp @@ -2682,13 +2683,13 @@ Sets mark to the value of point when this command is run." (defun comint-clear-buffer () "Clear the comint buffer." - (interactive) + (interactive nil comint-mode) (let ((comint-buffer-maximum-size 0)) (comint-truncate-buffer))) (defun comint-interrupt-subjob () "Interrupt the current subjob." - (interactive) + (interactive nil comint-mode) (comint-skip-input) (interrupt-process nil comint-ptyp) ;; (process-send-string nil "\n") @@ -2696,13 +2697,13 @@ Sets mark to the value of point when this command is run." (defun comint-kill-subjob () "Send kill signal to the current subjob." - (interactive) + (interactive nil comint-mode) (comint-skip-input) (kill-process nil comint-ptyp)) (defun comint-quit-subjob () "Send quit signal to the current subjob." - (interactive) + (interactive nil comint-mode) (comint-skip-input) (quit-process nil comint-ptyp)) @@ -2713,14 +2714,14 @@ WARNING: if there is no current subjob, you can end up suspending the top-level process running in the buffer. If you accidentally do this, use \\[comint-continue-subjob] to resume the process. (This is not a problem with most shells, since they ignore this signal.)" - (interactive) + (interactive nil comint-mode) (comint-skip-input) (stop-process nil comint-ptyp)) (defun comint-continue-subjob () "Send CONT signal to process buffer's process group. Useful if you accidentally suspend the top-level process." - (interactive) + (interactive nil comint-mode) (continue-process nil comint-ptyp)) (defun comint-skip-input () @@ -2741,7 +2742,7 @@ called this function are inserted into the buffer." (defun comint-kill-input () "Kill all text from last stuff output by interpreter to point." - (interactive) + (interactive nil comint-mode) (let ((pmark (process-mark (get-buffer-process (current-buffer))))) (if (> (point) (marker-position pmark)) (kill-region pmark (point))))) @@ -2749,7 +2750,7 @@ called this function are inserted into the buffer." (defun comint-delchar-or-maybe-eof (arg) "Delete ARG characters forward or send an EOF to subprocess. Sends an EOF only if point is at the end of the buffer and there is no input." - (interactive "p") + (interactive "p" comint-mode) (let ((proc (get-buffer-process (current-buffer)))) (if (and (eobp) proc (= (point) (marker-position (process-mark proc)))) (comint-send-eof) @@ -2757,7 +2758,7 @@ Sends an EOF only if point is at the end of the buffer and there is no input." (defun comint-send-eof () "Send an EOF to the current buffer's process." - (interactive) + (interactive nil comint-mode) (comint-send-input t t) (process-send-eof)) @@ -2769,7 +2770,7 @@ by lines that match `comint-prompt-regexp'. With prefix argument N, search for Nth previous match. If N is negative, find the next or Nth next match." - (interactive (comint-regexp-arg "Backward input matching (regexp): ")) + (interactive (comint-regexp-arg "Backward input matching (regexp): ") comint-mode) (if comint-use-prompt-regexp ;; Use comint-prompt-regexp (let* ((re (concat comint-prompt-regexp ".*" regexp)) @@ -2801,7 +2802,7 @@ by lines that match `comint-prompt-regexp'. With prefix argument N, search for Nth following match. If N is negative, find the previous or Nth previous match." - (interactive (comint-regexp-arg "Forward input matching (regexp): ")) + (interactive (comint-regexp-arg "Forward input matching (regexp): ") comint-mode) (comint-backward-matching-input regexp (- n))) @@ -2810,7 +2811,7 @@ If N is negative, find the previous or Nth previous match." If `comint-use-prompt-regexp' is nil, then this means the beginning of the Nth next `input' field, otherwise, it means the Nth occurrence of text matching `comint-prompt-regexp'." - (interactive "^p") + (interactive "^p" comint-mode) (if comint-use-prompt-regexp ;; Use comint-prompt-regexp (let ((paragraph-start comint-prompt-regexp)) @@ -2847,7 +2848,7 @@ text matching `comint-prompt-regexp'." If `comint-use-prompt-regexp' is nil, then this means the beginning of the Nth previous `input' field, otherwise, it means the Nth occurrence of text matching `comint-prompt-regexp'." - (interactive "^p") + (interactive "^p" comint-mode) (comint-next-prompt (- n))) ;; State used by `comint-insert-previous-argument' when cycling. @@ -2875,7 +2876,7 @@ from progressively earlier commands (using the value of INDEX specified with the first command). Values of INDEX < 0 count from the end, so INDEX = -1 is the last argument. This command is like \"M-.\" in Bash and zsh." - (interactive "P") + (interactive "P" comint-mode) (unless (null index) (setq index (prefix-numeric-value index))) (cond ((eq last-command this-command) @@ -2949,7 +2950,7 @@ with negative arguments.) If COUNT is zero, kill current line but exclude the trailing newline. The read-only status of newlines is updated with `comint-update-fence', if necessary." - (interactive "p") + (interactive "p" comint-mode) (let ((inhibit-read-only t) (inhibit-field-text-motion t)) (kill-whole-line count) (when (>= count 0) (comint-update-fence)))) @@ -2968,7 +2969,7 @@ prompts should stay at the beginning of a line. If this is not the case, this command just calls `kill-region' with all read-only properties intact. The read-only status of newlines is updated using `comint-update-fence', if necessary." - (interactive "r") + (interactive "r" comint-mode) (save-excursion (let* ((true-beg (min beg end)) (true-end (max beg end)) @@ -3363,7 +3364,7 @@ Completion is dependent on the value of `comint-completion-addsuffix', completions listing is dependent on the value of `comint-completion-autolist'. Returns t if successful." - (interactive) + (interactive nil comint-mode) (when (comint--match-partial-filename) (unless (window-minibuffer-p) (message "Completing file name...")) @@ -3438,7 +3439,7 @@ variables (e.g. $HOME), `~'s, `..', and `.', and making the filename absolute. For expansion see `expand-file-name' and `substitute-in-file-name'. For completion see `comint-dynamic-complete-filename'." - (interactive) + (interactive nil comint-mode) (let ((filename (comint-match-partial-filename))) (when filename (replace-match (expand-file-name filename) t t) @@ -3446,7 +3447,7 @@ filename absolute. For expansion see `expand-file-name' and (defun comint-dynamic-list-filename-completions () "Display a list of possible completions for the filename at point." - (interactive) + (interactive nil comint-mode) (let* ((data (comint--complete-file-name-data)) (minibuffer-completion-table (nth 2 data)) (minibuffer-completion-predicate nil) @@ -3534,7 +3535,7 @@ the completions." "After fetching a line from input history, this fetches the following line. In other words, this recalls the input line after the line you recalled last. You can use this to repeat a sequence of input lines." - (interactive) + (interactive nil comint-mode) (if comint-save-input-ring-index (progn (setq comint-input-ring-index (1+ comint-save-input-ring-index)) @@ -3548,7 +3549,7 @@ to be sent along with this line. Use \\[comint-send-input] to send all the accumulated input, at once. The entire accumulated text becomes one item in the input history when you send it." - (interactive) + (interactive nil comint-mode) (when-let* ((proc (get-buffer-process (current-buffer))) (pmark (process-mark proc)) ((or (marker-position comint-accum-marker) @@ -3573,7 +3574,7 @@ when you send it." "Move point to the process mark. The process mark separates output, and input already sent, from input that has not yet been sent." - (interactive) + (interactive nil comint-mode) (let ((proc (or (get-buffer-process (current-buffer)) (user-error "Current buffer has no process")))) (goto-char (process-mark proc)) @@ -3591,14 +3592,14 @@ from input that has not yet been sent. Ordinarily, the process mark is at the beginning of the current input line; but if you have used \\[comint-accumulate] to send multiple lines at once, the process mark is at the beginning of the accumulated input." - (interactive) + (interactive nil comint-mode) (if (not (eq last-command 'comint-bol-or-process-mark)) (comint-bol nil) (comint-goto-process-mark))) (defun comint-set-process-mark () "Set the process mark at point." - (interactive) + (interactive nil comint-mode) (let ((proc (or (get-buffer-process (current-buffer)) (user-error "Current buffer has no process")))) (set-marker (process-mark proc) (point)) @@ -3755,7 +3756,7 @@ and does not normally need to be invoked by the end user or programmer." (defun comint-redirect-cleanup () "End a Comint redirection. See `comint-redirect-send-command'." - (interactive) + (interactive nil comint-mode) ;; Release the last redirected string (setq comint-redirect-previous-input-string nil) ;; Restore the process filter @@ -3864,7 +3865,7 @@ This function does not need to be invoked by the end user." With prefix arg ECHO, echo output in process buffer. If NO-DISPLAY is non-nil, do not show the output buffer." - (interactive "sCommand: \nBOutput Buffer: \nP") + (interactive "sCommand: \nBOutput Buffer: \nP" comint-mode) (let ((process (get-buffer-process (current-buffer)))) (if process (comint-redirect-send-command-to-process @@ -3878,7 +3879,7 @@ If NO-DISPLAY is non-nil, do not show the output buffer." With prefix arg, echo output in process buffer. If NO-DISPLAY is non-nil, do not show the output buffer." - (interactive "sCommand: \nBOutput Buffer: \nbProcess Buffer: \nP") + (interactive "sCommand: \nBOutput Buffer: \nbProcess Buffer: \nP" comint-mode) (let* (;; The process buffer (process-buffer (if (processp process) (process-buffer process) @@ -4047,6 +4048,7 @@ This function signals an error if `comint-use-prompt-regexp' is non-nil. Input fontification isn't compatible with this setting." :lighter nil + :interactive (comint-mode) (if comint-fontify-input-mode (let ((success nil)) (unwind-protect commit d1d031aea69b3ab45034716048a2592fcbfd7358 Author: nibon7 Date: Tue Mar 26 17:24:33 2024 +0800 eglot: Add blueprint language server (Bug#70015) * lisp/progmodes/eglot.el (eglot-server-programs): Add blueprint-compiler. diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el index 0ba69f66f0d..94b45abe1d8 100644 --- a/lisp/progmodes/eglot.el +++ b/lisp/progmodes/eglot.el @@ -332,7 +332,8 @@ automatically)." ((uiua-ts-mode uiua-mode) . ("uiua" "lsp")) (sml-mode . ,(lambda (_interactive project) - (list "millet-ls" (project-root project))))) + (list "millet-ls" (project-root project)))) + ((blueprint-mode blueprint-ts-mode) . ("blueprint-compiler" "lsp"))) "How the command `eglot' guesses the server to start. An association list of (MAJOR-MODE . CONTACT) pairs. MAJOR-MODE identifies the buffers that are to be managed by a specific commit c97e7a2da2e5707fc94c2c5e2ddd5f2395cdb80b Author: kobarity Date: Sat Feb 24 23:11:02 2024 +0900 Improve fontification of Python assignments with type hints * lisp/progmodes/python.el (python-font-lock-keywords-maximum-decoration): Fontify type hints of assignment statement. (Bug#69357) * test/lisp/progmodes/python-tests.el (python-font-lock-assignment-statement-11) (python-font-lock-assignment-statement-12) (python-font-lock-assignment-statement-13) (python-font-lock-assignment-statement-18): Add fontification of type hints. (python-font-lock-assignment-statement-19): New test. diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index 831bec7f4af..360936c9efd 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -794,6 +794,25 @@ sign in chained assignment." ) symbol-end) . font-lock-type-face) + ;; single assignment with/without type hints, e.g. + ;; a: int = 5 + ;; b: Tuple[Optional[int], Union[Sequence[str], str]] = (None, 'foo') + ;; c: Collection = {1, 2, 3} + ;; d: Mapping[int, str] = {1: 'bar', 2: 'baz'} + (,(python-font-lock-assignment-matcher + (python-rx (or line-start ?\;) (* space) + grouped-assignment-target (* space) + (? ?: (* space) (group (+ not-simple-operator)) (* space)) + (group assignment-operator))) + (1 font-lock-variable-name-face) + (3 'font-lock-operator-face) + (,(python-rx symbol-name) + (progn + (when-let ((type-start (match-beginning 2))) + (goto-char type-start)) + (match-end 0)) + nil + (0 font-lock-type-face))) ;; multiple assignment ;; (note that type hints are not allowed for multiple assignments) ;; a, b, c = 1, 2, 3 @@ -826,18 +845,6 @@ sign in chained assignment." (match-beginning 2)) ; limit the search until the assignment nil (1 font-lock-variable-name-face))) - ;; single assignment with type hints, e.g. - ;; a: int = 5 - ;; b: Tuple[Optional[int], Union[Sequence[str], str]] = (None, 'foo') - ;; c: Collection = {1, 2, 3} - ;; d: Mapping[int, str] = {1: 'bar', 2: 'baz'} - (,(python-font-lock-assignment-matcher - (python-rx (or line-start ?\;) (* space) - grouped-assignment-target (* space) - (? ?: (* space) (+ not-simple-operator) (* space)) - (group assignment-operator))) - (1 font-lock-variable-name-face) - (2 'font-lock-operator-face)) ;; special cases ;; (a) = 5 ;; [a] = 5, diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index f50797953c3..2960cca2c06 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -391,7 +391,11 @@ p = (1 + 2) (python-tests-assert-faces "b: Tuple[Optional[int], Union[Sequence[str], str]] = (None, 'foo')" '((1 . font-lock-variable-name-face) (2) + (4 . font-lock-type-face) (9) + (10 . font-lock-type-face) (18) (19 . font-lock-builtin-face) (22) + (25 . font-lock-type-face) (30) + (31 . font-lock-type-face) (39) (40 . font-lock-builtin-face) (43) (46 . font-lock-builtin-face) (49) (52 . font-lock-operator-face) (53) @@ -402,12 +406,14 @@ p = (1 + 2) (python-tests-assert-faces "c: Collection = {1, 2, 3}" '((1 . font-lock-variable-name-face) (2) + (4 . font-lock-type-face) (14) (15 . font-lock-operator-face) (16)))) (ert-deftest python-font-lock-assignment-statement-13 () (python-tests-assert-faces "d: Mapping[int, str] = {1: 'bar', 2: 'baz'}" '((1 . font-lock-variable-name-face) (2) + (4 . font-lock-type-face) (11) (12 . font-lock-builtin-face) (15) (17 . font-lock-builtin-face) (20) (22 . font-lock-operator-face) (23) @@ -472,14 +478,28 @@ def f(x: CustomInt) -> CustomInt: (58 . font-lock-operator-face) (59) (62 . font-lock-operator-face) (63) (70 . font-lock-variable-name-face) (72) + (74 . font-lock-type-face) (82) + (83 . font-lock-type-face) (92) (94 . font-lock-operator-face) (95) (102 . font-lock-operator-face) (103) (111 . font-lock-variable-name-face) (114) + (116 . font-lock-type-face) (125) (126 . font-lock-operator-face) (127) (128 . font-lock-builtin-face) (131) (136 . font-lock-operator-face) (137) (144 . font-lock-keyword-face) (150)))) +(ert-deftest python-font-lock-assignment-statement-19 () + (python-tests-assert-faces + "a: List[List[CustomInt], List[CustomInt]] = []" + '((1 . font-lock-variable-name-face) (2) + (4 . font-lock-type-face) (8) + (9 . font-lock-type-face) (13) + (14 . font-lock-type-face) (23) + (26 . font-lock-type-face) (30) + (31 . font-lock-type-face) (40) + (43 . font-lock-operator-face) (44)))) + (ert-deftest python-font-lock-operator-1 () (python-tests-assert-faces "1 << 2 ** 3 == +4%-5|~6&7^8%9" commit bbb3038ad9feb1f37e4bef7151b2bc6f18c4123d Author: Andrea Corallo Date: Sat May 18 22:17:58 2024 +0200 * admin/syncdoc-type-hierarchy.el (syncdoc-make-type-table): Clean-up quote. diff --git a/admin/syncdoc-type-hierarchy.el b/admin/syncdoc-type-hierarchy.el index ed827844d0b..7f6b7495d00 100644 --- a/admin/syncdoc-type-hierarchy.el +++ b/admin/syncdoc-type-hierarchy.el @@ -110,7 +110,7 @@ do (cl-incf x (1+ child-len)) ) do (insert "\n"))) (require 'org-table) - (declare-function 'org-table-align "org") + (declare-function org-table-align "org") (org-table-align))) (defun syncdoc-update-type-hierarchy0 () commit e75921a1dcd8f4742e5bfbee7ca9b11016836e9e Author: Stefan Kangas Date: Sat May 18 21:28:49 2024 +0200 ; * etc/NEWS: Announce last change. diff --git a/etc/NEWS b/etc/NEWS index e92fc41c4b6..86ed99505d9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1755,6 +1755,17 @@ that is, buffers not visiting a file and whose names start with a space. Previously, such buffers were never shown. This command is bound to 'I' in Buffer Menu mode. +--- +*** nXML Mode now comes with schemas for Mono/.NET development. +The following new XML schemas are now supported: +- MSBuild project files +- Dotnet package properties files +- Dotnet resource extension files +- Dotnet Application config files +- Nuget config file +- Nuget package specification file +- Nuget packages config file + * New Modes and Packages in Emacs 30.1 commit e74eedaa2e34d7fd1c3ba9bd2632468bf36d5774 Author: Jostein Kjønigsen Date: Thu Feb 15 21:54:14 2024 +0100 nxml-mode: Add schemas for Mono/.NET related files * etc/schema/dotnet-appconfig.rnc: * etc/schema/dotnet-packages-config.rnc: * etc/schema/dotnet-packages-props.rnc: * etc/schema/dotnet-resx.rnc: * etc/schema/msbuild.rnc: * etc/schema/nuget.rnc: * etc/schema/nuspec.rnc: New files. * etc/schema/README: Document copyright status of above new files. * etc/schema/schemas.xml: Use above new files to support Mono/.NET development related XML files. This change was discussed in: https://lists.gnu.org/r/emacs-devel/2024-02/msg00638.html diff --git a/etc/schema/README b/etc/schema/README index 08dfe45dfbb..7611652762c 100644 --- a/etc/schema/README +++ b/etc/schema/README @@ -113,3 +113,23 @@ Software License: specific, written prior permission. Title to copyright in this software and any associated documentation will at all times remain with copyright holders. + + +The following files are related to .NET development: + + dotnet-appconfig.rnc dotnet-packages-config.rnc + dotnet-packages.props dotnet-resx.rnc msbuild.rnc nuget.rnc + nuspec.rnc + +These files are derived/inferred from files from numerous .NET projects, +whose contents have been created based on public documentation provided +by Microsoft, or created using the documentation as is. + +Links to various related resources: +- app.config: https://learn.microsoft.com/en-us/dotnet/framework/configure-apps/file-schema/ +- Directory.Packages.Props: https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management +- MSBuild: https://learn.microsoft.com/en-us/visualstudio/msbuild +- Nuspec: https://learn.microsoft.com/en-us/nuget/reference/nuspec +- Nuget.config: https://learn.microsoft.com/en-us/nuget/reference/nuget-config-file +- Packages.config: https://learn.microsoft.com/en-us/nuget/reference/packages-config +- Resx: Xsd-schema as included in default Resx-files generated by Resxen.exe diff --git a/etc/schema/dotnet-appconfig.rnc b/etc/schema/dotnet-appconfig.rnc new file mode 100644 index 00000000000..7e108672ed9 --- /dev/null +++ b/etc/schema/dotnet-appconfig.rnc @@ -0,0 +1,411 @@ +default namespace = "" +namespace ns1 = "http://schemas.microsoft.com/.NetConfiguration/v2.0" +namespace ns2 = "urn:schemas-microsoft-com:asm.v1" +namespace xdt = "http://schemas.microsoft.com/XML-Document-Transform" + +start = + element configuration { + element configSections { (section | sectionGroup)* }?, + element system.web.webPages.razor { + element host { + attribute factoryType { text } + }, + pages + }?, + (system.web + | system.webServer + | element location { + attribute inheritInChildApplications { xsd:boolean }?, + attribute path { text }?, + system.web?, + system.webServer? + } + | element runtime { + element loadFromRemoteSources { + attribute enabled { xsd:boolean } + }?, + element ns2:assemblyBinding { + attribute appliesTo { xsd:NCName }?, + element ns2:dependentAssembly { + element ns2:Paket { xsd:NCName }?, + element ns2:assemblyIdentity { + attribute culture { xsd:NCName }?, + attribute name { xsd:NCName }, + attribute publicKeyToken { xsd:NMTOKEN } + }, + element ns2:bindingRedirect { + attribute newVersion { xsd:NMTOKEN }, + attribute oldVersion { xsd:NMTOKEN } + } + }+ + }+ + } + | element startup { + attribute useLegacyV2RuntimeActivationPolicy { xsd:boolean }?, + element supportedRuntime { + attribute sku { text }, + attribute version { xsd:NCName } + } + } + | element system.codedom { + element compilers { + element compiler { + attribute compilerOptions { text }?, + attribute extension { xsd:NMTOKEN }, + attribute language { text }, + attribute type { text }, + attribute warningLevel { xsd:integer }, + element providerOption { + attribute name { xsd:NCName }, + attribute value { xsd:NCName } + }* + }+ + } + } + | element system.diagnostics { + element sources { + element source { + attribute name { xsd:NCName }, + element listeners { add }? + }+ + }?, + (element switches { empty }, + element sharedListeners { empty }, + element trace { + attribute autoflush { xsd:boolean } + })? + } + | element system.serviceModel { + element diagnostics { + element messageLogging { + attribute logEntireMessage { xsd:boolean }, + attribute logMalformedMessages { xsd:boolean }, + attribute logMessagesAtServiceLevel { xsd:boolean }, + attribute logMessagesAtTransportLevel { xsd:boolean }, + attribute maxMessagesToLog { xsd:integer }, + attribute maxSizeOfMessageToLog { xsd:integer } + } + }?, + (element behaviors { + element serviceBehaviors { + element behavior { + attribute name { text }?, + element serviceMetadata { + attribute httpGetEnabled { xsd:boolean }, + attribute httpsGetEnabled { xsd:boolean }? + }, + element serviceDebug { + attribute httpHelpPageEnabled { xsd:boolean }?, + attribute includeExceptionDetailInFaults { + xsd:boolean + } + }, + element dataContractSerializer { + attribute maxItemsInObjectGraph { xsd:integer } + }?, + (element serviceTelemetry { empty } + | element serviceThrottling { + attribute maxConcurrentCalls { xsd:integer }, + attribute maxConcurrentInstances { xsd:integer }, + attribute maxConcurrentSessions { xsd:integer } + })? + } + } + } + | element bindings { + element basicHttpBinding { + element binding { + attribute closeTimeout { xsd:time }?, + attribute maxBufferSize { xsd:integer }?, + attribute maxReceivedMessageSize { xsd:integer }?, + attribute name { xsd:NCName }?, + attribute openTimeout { xsd:time }?, + attribute receiveTimeout { xsd:time }?, + attribute sendTimeout { xsd:time }?, + element readerQuotas { + attribute maxArrayLength { xsd:integer }, + attribute maxBytesPerRead { xsd:integer }?, + attribute maxDepth { xsd:integer }?, + attribute maxNameTableCharCount { xsd:integer }?, + attribute maxStringContentLength { xsd:integer } + }?, + security? + }+ + }? + } + | element client { empty } + | element extensions { + element behaviorExtensions { add+ }, + (element bindingElementExtensions { add+ }, + element bindingExtensions { add+ })? + } + | element protocolMapping { add+ } + | element serviceHostingEnvironment { + attribute aspNetCompatibilityEnabled { xsd:boolean }?, + attribute multipleSiteBindingsEnabled { xsd:boolean }? + })*, + element services { + element service { + attribute behaviorConfiguration { xsd:NCName }?, + attribute name { text }, + element endpoint { + attribute address { xsd:NCName }?, + attribute binding { xsd:NCName }, + attribute bindingConfiguration { xsd:NCName }?, + attribute contract { xsd:NCName } + }+ + }+ + }? + })* + } + | element ns1:configuration { + element ns1:configSections { + element ns1:section { + attribute name { xsd:NCName }, + attribute requirePermission { xsd:boolean }, + attribute type { text } + } + }, + element ns1:appSettings { empty }, + element ns1:connectionStrings { empty }, + element ns1:system.web { + element ns1:compilation { + attribute debug { xsd:boolean }, + attribute defaultLanguage { text }, + attribute targetFramework { xsd:decimal } + }, + element ns1:authentication { + attribute mode { xsd:NCName } + }, + element ns1:httpModules { ns1.add }, + element ns1:pages { + attribute clientIDMode { xsd:NCName }, + attribute controlRenderingCompatibilityVersion { xsd:decimal } + } + }, + element ns1:system.webServer { + element ns1:modules { + attribute runAllManagedModulesForAllRequests { xsd:boolean }, + ns1.add + } + }, + element ns1:rewriter { + element ns1:rewrite { + attribute to { text }, + attribute url { text } + }+ + } + } +section = + element section { + attribute allowExeDefinition { xsd:NCName }?, + attribute name { xsd:NCName }, + attribute requirePermission { xsd:boolean }?, + attribute restartOnExternalChanges { xsd:boolean }?, + attribute type { text } + } +sectionGroup = + element sectionGroup { + attribute name { xsd:NCName }, + attribute type { text }?, + (section | sectionGroup)+ + } +pages = + element pages { + attribute clientIDMode { xsd:NCName }?, + attribute controlRenderingCompatibilityVersion { xsd:decimal }?, + attribute enableEventValidation { xsd:boolean }?, + attribute pageBaseType { xsd:NCName }?, + attribute theme { text }?, + attribute validateRequest { xsd:boolean }?, + attribute viewStateEncryptionMode { xsd:NCName }?, + element namespaces { add+ }? + } +add = + element add { + attribute assembly { text }?, + attribute binding { xsd:NCName }?, + attribute bindingConfiguration { text }?, + attribute connectionString { xsd:anyURI }?, + attribute initializationPage { text }?, + attribute initializeData { text }?, + attribute input { text }?, + attribute key { xsd:anyURI }?, + attribute matchType { xsd:NCName }?, + attribute modules { xsd:NCName }?, + attribute name { xsd:NCName }?, + attribute namespace { xsd:NCName }?, + attribute negate { xsd:boolean }?, + attribute path { text }?, + attribute preCondition { text }?, + attribute providerName { xsd:NCName }?, + attribute resourceType { xsd:NCName }?, + attribute responseBufferLimit { xsd:integer }?, + attribute scheme { xsd:NCName }?, + attribute scriptProcessor { text }?, + attribute type { text }?, + attribute validate { xsd:boolean }?, + attribute value { text }?, + attribute verb { text }?, + attribute xdt:Locator { text }?, + attribute xdt:Transform { xsd:NCName }? + } +security = + element security { + attribute mode { xsd:NCName }?, + attribute xdt:Transform { xsd:NCName }?, + (element requestFiltering { + attribute removeServerHeader { xsd:boolean }, + element requestLimits { + attribute maxAllowedContentLength { xsd:integer } + }? + } + | element transport { + attribute clientCredentialType { xsd:NCName } + })? + } +system.webServer = + element system.webServer { + (element httpErrors { + attribute errorMode { xsd:NCName }?, + attribute existingResponse { xsd:NCName }, + (remove+, + element error { + attribute path { text }, + attribute prefixLanguageFilePath { text }, + attribute responseMode { xsd:NCName }, + attribute statusCode { xsd:integer } + }+)? + } + | element staticContent { + element mimeMap { + attribute fileExtension { xsd:NMTOKEN }, + attribute mimeType { text } + }+ + })?, + (element applicationInitialization { + attribute xdt:Transform { xsd:NCName }, + add + } + | element rewrite { + element rules { + clear + | element rule { + attribute name { text }, + attribute stopProcessing { xsd:boolean }, + element match { + attribute url { text } + }, + element conditions { + attribute logicalGrouping { xsd:NCName }, + add+ + }?, + element action { + attribute redirectType { xsd:NCName }?, + attribute type { xsd:NCName }, + attribute url { text } + } + } + } + })?, + (security + | element aspNetCore { + attribute arguments { text }?, + attribute hostingModel { xsd:NCName }?, + attribute processPath { text }?, + attribute requestTimeout { xsd:time }?, + attribute stdoutLogEnabled { xsd:boolean }?, + attribute stdoutLogFile { text }?, + attribute xdt:Transform { text }? + } + | element handlers { (add | remove)+ } + | element httpProtocol { + attribute xdt:Transform { xsd:NCName }?, + element customHeaders { clear?, remove+ } + } + | element modules { + attribute runAllManagedModulesForAllRequests { xsd:boolean }?, + (add | remove)* + } + | element validation { + attribute validateIntegratedModeConfiguration { xsd:boolean } + })*, + element directoryBrowse { + attribute enabled { xsd:boolean } + }? + } +system.web = + element system.web { + element authorization { + element allow { + attribute users { text } + } + } + | (pages + | element authentication { + attribute mode { xsd:NCName } + } + | element compilation { + attribute debug { xsd:boolean }?, + attribute targetFramework { xsd:NMTOKEN }?, + attribute tempDirectory { text }?, + attribute xdt:Transform { text }?, + element assemblies { add+ }? + } + | element customErrors { + attribute defaultRedirect { text }?, + attribute mode { xsd:NCName }, + attribute redirectMode { xsd:NCName }? + } + | element globalization { + attribute requestEncoding { xsd:NCName }, + attribute responseEncoding { xsd:NCName } + } + | element httpHandlers { add+ } + | element httpModules { add* } + | element httpRuntime { + attribute appRequestQueueLimit { xsd:integer }?, + attribute enableVersionHeader { xsd:boolean }?, + attribute executionTimeout { xsd:integer }?, + attribute maxRequestLength { xsd:integer }?, + attribute minFreeThreads { xsd:integer }?, + attribute minLocalRequestFreeThreads { xsd:integer }?, + attribute requestPathInvalidCharacters { text }?, + attribute requestValidationMode { xsd:decimal }?, + attribute targetFramework { xsd:NMTOKEN }?, + attribute useFullyQualifiedRedirectUrl { xsd:boolean }? + } + | element identity { + attribute impersonate { xsd:boolean } + } + | element machineKey { + attribute validation { xsd:NCName } + } + | element sessionState { + attribute cookieSameSite { xsd:NCName }?, + attribute cookieless { xsd:boolean }, + attribute mode { xsd:NCName }, + attribute stateConnectionString { text }?, + attribute timeout { xsd:integer } + } + | element xhtmlConformance { + attribute mode { xsd:NCName } + })* + } +Globalization = + element Globalization { + element ResourceProviders { empty } + | add+ + } +ns1.add = + element ns1:add { + attribute name { xsd:NCName }, + attribute type { text } + } +remove = + element remove { + attribute name { xsd:NCName }?, + attribute statusCode { xsd:integer }?, + attribute subStatusCode { xsd:integer }? + } +clear = element clear { empty } diff --git a/etc/schema/dotnet-packages-config.rnc b/etc/schema/dotnet-packages-config.rnc new file mode 100644 index 00000000000..702f11aca31 --- /dev/null +++ b/etc/schema/dotnet-packages-config.rnc @@ -0,0 +1,11 @@ +default namespace = "" + +start = + element packages { + element package { + attribute id { xsd:NCName }, + attribute targetFramework { xsd:NCName }?, + attribute allowedVersions { xsd:NCName }?, + attribute version { xsd:NMTOKEN } + }+ + } diff --git a/etc/schema/dotnet-packages-props.rnc b/etc/schema/dotnet-packages-props.rnc new file mode 100644 index 00000000000..18c689eb2dd --- /dev/null +++ b/etc/schema/dotnet-packages-props.rnc @@ -0,0 +1,22 @@ +default namespace = "" + +start = + element Project { + element PropertyGroup { + element ManagePackageVersionsCentrally { xsd:boolean }, + element CentralPackageTransitivePinningEnabled { xsd:boolean }, + element CentralPackageVersionOverrideEnabled { xsd:boolean } + }?, + element ItemGroup { + attribute Condition { text }?, + (element GlobalPackageReference { + attribute Condition { text }?, + attribute Include { xsd:NCName }, + attribute Version { xsd:NMTOKEN } + }+ + | element PackageVersion { + attribute Include { xsd:NCName }, + attribute Version { text } + }+) + }+ + } diff --git a/etc/schema/dotnet-resx.rnc b/etc/schema/dotnet-resx.rnc new file mode 100644 index 00000000000..26b77e47527 --- /dev/null +++ b/etc/schema/dotnet-resx.rnc @@ -0,0 +1,57 @@ +default namespace = "" +namespace msdata = "urn:schemas-microsoft-com:xml-msdata" +namespace xsd = "http://www.w3.org/2001/XMLSchema" + +start = + element root { + element xsd:schema { + attribute id { xsd:NCName }, + element xsd:import { + attribute namespace { xsd:anyURI } + }?, + xsd.element + }, + element resheader { + attribute name { xsd:NCName }, + value + }+, + (element assembly { + attribute alias { xsd:NCName }, + attribute name { text } + } + | element data { + attribute mimetype { text }?, + attribute name { text }, + attribute type { text }?, + attribute xml:space { xsd:NCName }?, + value + } + | element metadata { + attribute name { xsd:NCName }, + attribute type { text }, + value + })* + } +xsd.element = + element xsd:element { + attribute minOccurs { xsd:integer }?, + attribute name { xsd:NCName }, + attribute type { xsd:NMTOKEN }?, + attribute msdata:IsDataSet { xsd:boolean }?, + attribute msdata:Ordinal { xsd:integer }?, + element xsd:complexType { + element xsd:choice { + attribute maxOccurs { xsd:NCName }, + xsd.element+ + }?, + element xsd:sequence { xsd.element+ }?, + element xsd:attribute { + attribute name { xsd:NCName }?, + attribute ref { xsd:NMTOKEN }?, + attribute type { xsd:NMTOKEN }?, + attribute use { xsd:NCName }?, + attribute msdata:Ordinal { xsd:integer }? + }* + }* + } +value = element value { text } diff --git a/etc/schema/msbuild.rnc b/etc/schema/msbuild.rnc new file mode 100644 index 00000000000..9425bbdf0b9 --- /dev/null +++ b/etc/schema/msbuild.rnc @@ -0,0 +1,1041 @@ +default namespace = "" +namespace ns1 = "http://schemas.microsoft.com/developer/msbuild/2003" + +start = Project | ns1.Project +Project = + element Project { + attribute Sdk { text }?, + (text + | ItemGroup + | PropertyGroup + | element Import { + attribute Project { text } + } + | element ProjectExtensions { + element VisualStudio { + element FlavorProperties { + attribute GUID { text }, + element WebProjectProperties { + element UseIIS { xsd:NCName }, + element AutoAssignPort { xsd:NCName }, + element DevelopmentServerPort { xsd:integer }, + element DevelopmentServerVPath { text }, + element IISUrl { xsd:anyURI }, + element NTLMAuthentication { xsd:NCName }, + element UseCustomServer { xsd:NCName }, + element CustomServerUrl { empty }, + element SaveServerSettingsInUserFile { xsd:NCName } + } + } + | element UserProperties { + attribute configuration_4bicepconfig_1json__JsonSchema { + xsd:anyURI + } + } + } + } + | element Target { + attribute AfterTargets { xsd:NCName }?, + attribute BeforeTargets { xsd:NCName }?, + attribute Condition { text }?, + attribute DependsOnTargets { text }?, + attribute Inputs { text }?, + attribute Name { xsd:NCName }, + attribute Outputs { text }?, + (PropertyGroup + | (element RemoveDir { + attribute Condition { text }, + attribute Directories { text } + }, + element Delete { + attribute Condition { text }, + attribute Files { text } + }))?, + (ItemGroup + | element Error { + attribute Condition { text }, + attribute Text { text } + } + | element Exec { + attribute Command { text }, + attribute Condition { text }?, + attribute ContinueOnError { xsd:boolean }?, + attribute EnvironmentVariables { text }?, + attribute WorkingDirectory { text }?, + element Output { + attribute PropertyName { xsd:NCName }, + attribute TaskParameter { xsd:NCName } + }? + } + | element MakeDir { + attribute Directories { text } + } + | element Message { + attribute Condition { text }?, + attribute Importance { xsd:NCName }, + attribute Text { text } + })*, + (element Copy { + attribute DestinationFolder { text }, + attribute SourceFiles { text } + } + | element MSBuild { + attribute BuildInParallel { xsd:boolean }, + attribute Projects { text }, + attribute Properties { text }, + attribute Targets { xsd:NCName } + })? + })+ + } +ns1.Project = + element ns1:Project { + attribute DefaultTargets { xsd:NCName }?, + attribute ToolsVersion { xsd:decimal }?, + (text + | ns1.ItemGroup + | ns1.PropertyGroup + | element ns1:Choose { + element ns1:When { + attribute Condition { text }, + (ns1.PropertyGroup | ns1.ItemGroup+) + }+, + element ns1:Otherwise { ns1.ItemGroup }? + } + | element ns1:Import { + attribute Condition { text }?, + attribute Label { xsd:NCName }?, + attribute Project { text } + } + | element ns1:ProjectExtensions { + element ns1:VisualStudio { + element ns1:FlavorProperties { + attribute GUID { text }, + (element ns1:WebProjectProperties { + (element ns1:UseIIS { xsd:NCName }, + element ns1:AutoAssignPort { xsd:NCName }, + element ns1:DevelopmentServerPort { xsd:integer }, + element ns1:DevelopmentServerVPath { text }, + element ns1:IISUrl { xsd:anyURI }, + element ns1:NTLMAuthentication { xsd:NCName }, + element ns1:UseCustomServer { xsd:NCName }, + element ns1:CustomServerUrl { empty })?, + element ns1:SaveServerSettingsInUserFile { xsd:NCName } + } + | (element ns1:ProjectProperties { + attribute AddItemTemplatesGuid { text }, + attribute ApplicationType { xsd:NCName }, + attribute DebugInfoExeName { text }, + attribute HostName { xsd:NCName }, + attribute HostPackage { text }, + attribute Language { xsd:NCName }, + attribute OfficeVersion { xsd:decimal }, + attribute TemplatesPath { xsd:NCName }, + attribute VstxVersion { xsd:decimal } + }, + element ns1:Host { + attribute GeneratedCodeNamespace { xsd:NCName }, + attribute IconIndex { xsd:integer }, + attribute Name { xsd:NCName }, + attribute PublishedHash { text }, + element ns1:HostItem { + attribute Blueprint { xsd:NCName }, + attribute CanActivate { xsd:boolean }, + attribute CanonicalName { xsd:NCName }, + attribute Code { xsd:NCName }, + attribute GeneratedCode { xsd:NCName }, + attribute IconIndex { xsd:integer }, + attribute Name { xsd:NCName }, + attribute PublishedHash { text } + } + })) + } + | element ns1:UserProperties { + attribute Name { xsd:NCName } + } + } + } + | element ns1:Target { + attribute AfterTargets { xsd:NCName }?, + attribute BeforeTargets { xsd:NCName }?, + attribute Condition { text }?, + attribute Name { xsd:NCName }, + attribute Outputs { text }?, + (ns1.PropertyGroup + | element ns1:Error { + attribute Condition { text }, + attribute HelpKeyword { xsd:NCName }, + attribute Text { text } + }* + | (ns1.ItemGroup + | element ns1:MakeDir { + attribute Directories { text } + } + | element ns1:WriteCodeFragment { + attribute AssemblyAttributes { text }, + attribute Language { text }, + attribute OutputFile { text } + })*), + (element ns1:Copy { + attribute ContinueOnError { xsd:boolean }?, + attribute DestinationFolder { text }, + attribute OverwriteReadOnlyFiles { xsd:NCName }, + attribute SourceFiles { text } + } + | element ns1:CreateItem { + attribute Exclude { text }?, + attribute Include { text }, + ns1.Output + } + | element ns1:Delete { + attribute Files { text }, + attribute TreatErrorsAsWarnings { xsd:NCName } + } + | element ns1:Exec { + attribute Command { text }, + attribute WorkingDirectory { text }? + } + | element ns1:GetVersionParts { + attribute AssemblyPath { text }, + ns1.Output+ + } + | element ns1:Message { + attribute Importance { xsd:NCName }?, + attribute Text { text } + } + | element ns1:TokenReplace { + attribute Condition { text }?, + attribute Destination { text }, + attribute Path { text }, + attribute Replacement { text }, + attribute Token { text } + })*, + element ns1:CallTarget { + attribute Condition { text }?, + attribute Targets { xsd:NCName } + }? + } + | element ns1:UsingTask { + attribute AssemblyFile { text }, + attribute TaskFactory { xsd:NCName }, + attribute TaskName { xsd:NCName }, + element ns1:ParameterGroup { + (element ns1:Path { + attribute ParameterType { xsd:NCName }, + attribute Required { xsd:boolean } + }, + element ns1:Destination { + attribute ParameterType { xsd:NCName }, + attribute Required { xsd:boolean } + }, + element ns1:Token { + attribute ParameterType { xsd:NCName }, + attribute Required { xsd:boolean } + }, + element ns1:Replacement { + attribute ParameterType { xsd:NCName }, + attribute Required { xsd:boolean } + }) + | (element ns1:AssemblyPath { + attribute ParameterType { xsd:NCName }, + attribute Required { xsd:boolean } + }, + element ns1:MajorVersion { + attribute Output { xsd:boolean }, + attribute ParameterType { xsd:NCName } + }, + element ns1:MinorVersion { + attribute Output { xsd:boolean }, + attribute ParameterType { xsd:NCName } + }, + element ns1:BuildVersion { + attribute Output { xsd:boolean }, + attribute ParameterType { xsd:NCName } + }, + element ns1:RevisionVersion { + attribute Output { xsd:boolean }, + attribute ParameterType { xsd:NCName } + }) + }, + element ns1:Task { + element ns1:Using { + attribute Namespace { xsd:NCName } + }?, + element ns1:Code { + attribute Language { xsd:NCName }, + attribute Type { xsd:NCName }, + text + } + } + })+ + } +PropertyGroup = + element PropertyGroup { + attribute Condition { text }?, + attribute Label { xsd:NCName }?, + element TargetFrameworks { text }?, + (element DotnetMonoRepoVersion { xsd:NMTOKEN } + | (element CFBundleName { text }, + element CFBundleDisplayName { text }, + element CFBundleIdentifier { xsd:NCName }, + element CFBundleVersion { xsd:NMTOKEN }, + element CFBundleShortVersionString { xsd:NMTOKEN }, + element CFBundlePackageType { xsd:NCName }, + element CFBundleExecutable { xsd:NCName }, + element CFBundleIconFile { xsd:NCName }, + element NSPrincipalClass { xsd:NCName }, + element NSHighResolutionCapable { xsd:boolean }))?, + (element SoAssemblyFileVersion { + attribute Condition { text }, + xsd:NMTOKEN + }, + element SoReleaseVersion { + attribute Condition { text }, + text + })?, + (element AccelerateBuildsInVisualStudio { xsd:boolean } + | element AddLicenseAsEmbeddedResource { xsd:boolean } + | element AddNoticeAsEmbeddedResource { xsd:boolean } + | element AnalysisMode { xsd:NCName } + | element ApiName { + attribute Condition { text }, + xsd:NCName + } + | element AppConfig { xsd:NCName } + | element AppendTargetFrameworkToOutputPath { xsd:boolean } + | element ApplicationIcon { text } + | element ApplicationManifest { xsd:NCName } + | element AspNetCoreHostingModel { xsd:NCName } + | element AssemblyName { text } + | element AssemblyOriginatorKeyFile { text } + | element AssemblyTitle { text } + | element AssemblyVersion { xsd:NMTOKEN } + | element Authors { text } + | element AutoGenerateBindingRedirects { + attribute Condition { text }?, + xsd:boolean + } + | element AzureFunctionsVersion { xsd:NCName } + | element BicepCompileAfterTargets { xsd:NCName } + | element BicepCompileBeforeTargets { xsd:NCName } + | element BootstrapperEnabled { xsd:boolean } + | element BuildOutputTargetFolder { xsd:NCName } + | element BuildServerSideRenderer { xsd:boolean } + | element BuiltInComInteropSupport { xsd:boolean } + | element CentralPackageTransitivePinningEnabled { xsd:boolean } + | element CodeAnalysisTreatWarningsAsErrors { xsd:boolean } + | element Company { text } + | element CopyLocalLockFileAssemblies { xsd:boolean } + | element Copyright { text } + | element DebugType { + attribute Condition { text }?, + xsd:NCName + } + | element DefaultItemExcludes { text } + | element DefineConstants { text } + | element DelaySign { xsd:boolean } + | element Description { text } + | element Deterministic { xsd:boolean } + | element DisableImplicitNuGetFallbackFolder { xsd:boolean } + | element DisableTransitiveProjectReferences { xsd:boolean } + | element DockerDefaultTargetOS { xsd:NCName } + | element DockerfileContext { text } + | element EmbedUntrackedSources { xsd:boolean } + | element EnableCompressionInSingleFile { xsd:boolean } + | element EnableDefaultCompileItems { xsd:boolean } + | element EnableDefaultEmbeddedResourceItems { xsd:boolean } + | element EnableMSTestRunner { xsd:boolean } + | element EnableNETAnalyzers { xsd:boolean } + | element EnableNuget { xsd:boolean } + | element EnableTrimAnalyzer { xsd:boolean } + | element EnforceCodeStyleInBuild { xsd:boolean } + | element ErrorReport { xsd:NCName } + | element FileVersion { xsd:NMTOKEN } + | element FindInvalidProjectReferences { xsd:boolean } + | element GenerateAssemblyInfo { xsd:boolean } + | element GenerateBindingRedirectsOutputType { xsd:boolean } + | element GenerateDocumentationFile { xsd:NCName } + | element GeneratePackageOnBuild { xsd:NCName } + | element GenerateResourceUsePreserializedResources { xsd:boolean } + | element ImplicitUsings { xsd:NCName } + | element IncludeNativeLibrariesForSelfExtract { xsd:boolean } + | element IncludeSymbols { xsd:boolean } + | element IsPackable { xsd:boolean } + | element LangVersion { xsd:NMTOKEN } + | element ManagePackageVersionsCentrally { xsd:boolean } + | element MapFileExtensions { xsd:boolean } + | element NoPackageAnalysis { xsd:boolean } + | element NoWarn { text } + | element Nullable { xsd:NCName } + | element Optimize { xsd:boolean } + | element OutputPath { text } + | element OutputType { xsd:NCName } + | element PackAsTool { xsd:boolean } + | element PackageIcon { text } + | element PackageIconUrl { empty } + | element PackageId { text } + | element PackageLicenseFile { xsd:NCName } + | element PackageProjectUrl { xsd:anyURI } + | element PackageReleaseNotes { text } + | element PackageTags { text } + | element PlatformTarget { xsd:NCName } + | element Platforms { text } + | element Prefer32Bit { xsd:boolean } + | element ProduceReferenceAssembly { xsd:NCName } + | element Product { text } + | element ProjectGuid { text } + | element PublishRepositoryUrl { xsd:boolean } + | element PublishSingleFile { xsd:boolean } + | element RepositoryType { empty } + | element RepositoryUrl { empty } + | element RestoreLockedMode { + attribute Condition { text }, + xsd:boolean + } + | element RestorePackagesWithLockFile { xsd:boolean } + | element RestoreProjectStyle { xsd:NCName } + | element RootNamespace { text } + | element RunPostBuildEvent { xsd:NCName } + | element RunSettingsFilePath { text } + | element RuntimeIdentifier { xsd:NCName } + | element RuntimeIdentifiers { + attribute Condition { text }?, + text + } + | element SatelliteResourceLanguages { xsd:NCName } + | element SelfContained { xsd:boolean } + | element SignAssembly { xsd:NCName } + | element SoVersionOptions { xsd:NCName } + | element SpaRoot { text } + | element StartupObject { xsd:NCName } + | element Summary { text } + | element SupportedOSPlatformVersion { xsd:decimal } + | element SuppressTrimAnalysisWarnings { xsd:boolean } + | element SymbolPackageFormat { xsd:NCName } + | element TargetFramework { text } + | element Title { text } + | element ToolCommandName { xsd:NCName } + | element TreatWarningsAsErrors { xsd:boolean } + | element TrimMode { xsd:NCName } + | element TypeScriptCompileBlocked { + attribute Condition { text }?, + xsd:boolean + } + | element TypeScriptToolsVersion { xsd:NCName } + | element UseAppHost { xsd:boolean } + | element UseApplicationTrust { xsd:boolean } + | element UseWPF { xsd:boolean } + | element UseWindowsForms { xsd:boolean } + | element UserSecretsId { text } + | element Version { + attribute Condition { text }?, + text + } + | element WarningsAsErrors { text } + | element WarningsNotAsErrors { text } + | element WasmMainJSPath { text })*, + (element PackageRequireLicenseAcceptance { xsd:boolean } + | element _FunctionsSkipCleanOutput { xsd:boolean } + | (element OutDir { text }, + element ExcludeXmlAssemblyFiles { xsd:boolean }))?, + element EnableUnsafeBinaryFormatterSerialization { xsd:boolean }?, + (element AssemblySearchPaths { text } + | element AvaloniaUseCompiledBindingsByDefault { xsd:boolean } + | element BaseOutputPath { text } + | element BicepOutputStyle { xsd:NCName } + | element ContinuousIntegrationBuild { xsd:boolean } + | element DebugSymbols { xsd:boolean } + | element DefaultDocumentationIncludeUndocumentedItems { + xsd:boolean + } + | element DscZipFile { text } + | element EnableNoticeInPublishOutput { xsd:boolean } + | element GenerateDocumentation { xsd:boolean } + | element IncludeAllContentForSelfExtract { xsd:boolean } + | element IsTestProject { xsd:boolean } + | element NetSdk { xsd:NCName } + | element ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch { + xsd:NCName + } + | element ShouldIncludeNativeSkiaSharp { xsd:NCName } + | element TargetsForTfmSpecificBuildOutput { text } + | (element SccProjectName { xsd:NCName }, + element SccProvider { xsd:NCName }, + element SccAuxPath { xsd:NCName }, + element SccLocalPath { xsd:NCName }) + | (element GenerateNoticePackageVersion { xsd:NMTOKEN }, + element GenerateNoticeRetryCount { xsd:integer }, + element GenerateNoticeBatchSize { xsd:integer }, + element GenerateNoticeUseLocalFile { + attribute Condition { text }, + xsd:boolean + }, + element GenerateNoticeUpdateLocalFile { + attribute Condition { text }, + xsd:boolean + }) + | (element RunNswag { xsd:boolean }, + element RunNodeBuild { xsd:boolean }) + | (element PublishTrimmed { xsd:boolean }, + element JsonSerializerIsReflectionEnabledByDefault { + xsd:boolean + }) + | (element ApplicationId { xsd:NCName }, + element ApplicationVersion { xsd:integer }, + element ApplicationDisplayVersion { xsd:decimal }, + element AndroidPackageFormat { xsd:NCName }, + element AndroidEnableProfiledAot { xsd:NCName }) + | (element DefaultDocumentationFolder { text }, + element DefaultDocumentationLinksBaseUrl { text }, + element DefaultDocumentationLinksOutputFile { text }, + element DefaultDocumentationExternLinksFiles { text }, + element DefaultDocumentationConfigurationFile { text }))?, + element ServiceName { xsd:NCName }?, + (element RazorLangVersion { xsd:decimal } + | (element WebRoot { text }, + element WebProjectFile { text }, + element WebOutputPath { text }))?, + element ClientName { text }?, + element DisableDataAnnotationsParam { text }?, + (element AvaloniaVersion { xsd:NMTOKEN } + | element ContinuePackingAfterGeneratingNuspec { xsd:boolean } + | ((element NSwagGenerateExceptionClasses { xsd:boolean } + | element WrapResponseMethods { text })+, + element NSwagOptions { text }) + | (element DeployDefaultTargetFrameworkVersion { xsd:decimal }, + element VisualStudioVersion { + attribute Condition { text }, + xsd:decimal + }))? + } +ItemGroup = + element ItemGroup { + attribute Condition { text }?, + (element ApiClientGen { + attribute Include { xsd:NCName } + } + | element AvaloniaXaml { + attribute Remove { text } + } + | element BuildOutputInPackage { + attribute Include { text }, + attribute TargetPath { text } + } + | element InternalsVisibleTo { + attribute Condition { text }, + attribute Include { text } + } + | element ProjectsToPublish { + attribute Include { text } + } + | element Service { + attribute Include { text } + } + | element _ReferenceCopyLocalPaths { + attribute Include { text } + } + | element ClaimsRequirement { + attribute Include { xsd:NCName } + }*), + element WCFMetadata { + attribute Include { text } + }?, + (element AdditionalFiles { + attribute Remove { text } + } + | element SourceRoot { + attribute Include { text } + } + | element ApiClient { + attribute Include { xsd:NCName } + }*), + element FrameworkReference { + attribute Include { xsd:NCName } + }?, + (element COMReference { + attribute Include { xsd:NCName }, + element Guid { text }, + element VersionMajor { xsd:integer }, + element VersionMinor { xsd:integer }, + element Lcid { xsd:integer }, + element WrapperTool { xsd:NCName }, + element Isolated { xsd:NCName }, + EmbedInteropTypes + } + | element TrimmerRootDescriptor { + attribute Include { xsd:NCName } + } + | element Watch { + attribute Exclude { text }?, + attribute Include { text }?, + attribute Remove { text }? + }* + | element AvaloniaResource { + attribute Include { text }?, + attribute Remove { text }? + }* + | element OpenApiReference { + attribute ClassName { text }?, + attribute Include { text }, + attribute Namespace { text }?, + attribute Options { text }?, + element CodeGenerator { xsd:NCName }? + }*), + element Bicep { + attribute Exclude { text }?, + attribute Include { text }?, + attribute NoBuild { xsd:boolean }?, + attribute OutputFile { text }?, + attribute Update { text }?, + element OutputFile { text }? + }*, + (element Folder { + attribute Include { text } + }* + | element BicepParam { + attribute Include { text } + }*), + (element Compile { + attribute Include { text }?, + attribute Link { xsd:NCName }?, + attribute Remove { text }?, + attribute Update { text }?, + Link?, + (DependentUpon + | element AutoGen { xsd:NCName } + | element DesignTime { xsd:NCName })*, + (SubType + | element DesignTimeSharedInput { xsd:NCName })? + } + | element Content { + attribute CopyToOutputDirectory { xsd:NCName }?, + attribute CopyToPublishDirectory { xsd:NCName }?, + attribute Exclude { text }?, + attribute Include { text }?, + attribute Link { text }?, + attribute PackagePath { text }?, + attribute Remove { text }?, + attribute Update { text }?, + Link?, + (CopyToOutputDirectory + | CopyToPublishDirectory + | DependentUpon + | ExcludeFromSingleFile + | SubType)* + } + | element EmbeddedResource { + attribute Condition { text }?, + attribute Include { text }?, + attribute Link { text }?, + attribute LogicalName { text }?, + attribute Remove { text }?, + attribute Update { text }?, + attribute WithCulture { xsd:boolean }?, + CopyToOutputDirectory?, + element CustomToolNamespace { xsd:NCName }?, + element LogicalName { text }?, + (Generator | LastGenOutput)*, + SubType?, + Link?, + (DependentUpon + | element WithCulture { xsd:boolean })? + } + | element None { + attribute CopyToOutputDirectory { xsd:NCName }?, + attribute CopyToPublishDirectory { xsd:NCName }?, + attribute Exclude { text }?, + attribute Include { text }?, + attribute Link { xsd:NCName }?, + attribute Pack { xsd:boolean }?, + attribute PackagePath { text }?, + attribute Remove { text }?, + attribute Update { text }?, + Generator?, + (LastGenOutput + | SubType + | (element Pack { xsd:NCName } + | element PackagePath { empty })*), + CopyToOutputDirectory?, + (CopyToPublishDirectory | DependentUpon)? + } + | element Resource { + attribute Include { text } + } + | element WCFMetadataStorage { + attribute Include { text } + })*, + (element AndroidResource { + attribute Include { xsd:NCName }, + Link + } + | element DesignData { + attribute Include { text } + } + | element WasmExtraFilesToDeploy { + attribute Include { text } + } + | element Using { + attribute Alias { xsd:NCName }?, + attribute Include { xsd:NCName } + }* + | element DocumentName { + attribute Include { xsd:NCName } + }* + | (element PackageDownload { + attribute Include { xsd:NCName }, + attribute Version { text } + } + | element PackageReference { + attribute Condition { text }?, + attribute ExcludeAssets { xsd:NCName }?, + attribute Include { text }, + attribute PrivateAssets { xsd:NCName }?, + attribute Version { text }?, + (element IncludeAssets { text } + | element PrivateAssets { xsd:NCName })* + } + | element ProjectReference { + attribute Include { text }?, + attribute PrivateAssets { xsd:NCName }?, + attribute Remove { xsd:NCName }?, + (element Properties { text } + | (Project, + element Name { xsd:NCName }))? + } + | element Reference { + attribute Include { text }, + (EmbedInteropTypes + | element HintPath { + attribute Condition { text }?, + text + } + | element Private { xsd:NCName } + | element SpecificVersion { xsd:NCName })* + })* + | (element DistFiles { + attribute Condition { text }?, + attribute Include { text } + }+, + element ResolvedFileToPublish { + attribute Exclude { text }, + attribute Include { text }, + element RelativePath { text }, + CopyToPublishDirectory, + ExcludeFromSingleFile? + }) + | element TypeScriptCompile { + attribute Include { text }?, + attribute Remove { text }?, + DependentUpon? + }* + | element Page { + attribute Generator { xsd:NMTOKEN }?, + attribute Include { text }?, + attribute Remove { text }?, + attribute SubType { xsd:NCName }? + }*) + } +ns1.PropertyGroup = + element ns1:PropertyGroup { + attribute Condition { text }?, + (element ns1:NugetFolder { text }, + element ns1:BuildFolder { text })?, + element ns1:SoReleaseVersion { text }?, + (element ns1:ApplicationManifest { xsd:NCName } + | element ns1:ErrorText { text } + | element ns1:__paket__NETStandard_Library_targets { text })?, + element ns1:PreBuildEvent { + attribute Condition { text }?, + text + }?, + element ns1:__paket__MSTest_TestFramework_targets { text }?, + element ns1:SoLegacyVersion { xsd:NCName }?, + element ns1:SoBetaTag { empty }?, + element ns1:ComputerName { text }?, + element ns1:__paket__MSTest_TestAdapter_props { text }?, + element ns1:__paket__MSTest_TestAdapter_targets { text }?, + element ns1:MinimumVisualStudioVersion { xsd:decimal }?, + (element ns1:AppDesignerFolder { xsd:NCName } + | element ns1:ApplicationRevision { xsd:integer } + | element ns1:ApplicationVersion { text } + | element ns1:AssemblyName { xsd:NCName } + | element ns1:AssemblyOriginatorKeyFile { text } + | element ns1:AutoGenerateBindingRedirects { xsd:boolean } + | element ns1:AutoIncrementApplicationRevision { xsd:boolean } + | element ns1:BootstrapperEnabled { xsd:boolean } + | element ns1:CodeAnalysisRuleSet { text } + | element ns1:Configuration { + attribute Condition { text }, + xsd:NCName + } + | element ns1:DebugSymbols { xsd:boolean } + | element ns1:DebugType { xsd:NCName } + | element ns1:DefineConstants { text } + | element ns1:DependsOnNETStandard { xsd:NCName } + | element ns1:Deterministic { xsd:boolean } + | element ns1:DocumentationFile { text } + | element ns1:EnableUnmanagedDebugging { xsd:boolean } + | element ns1:ErrorReport { xsd:NCName } + | element ns1:FileAlignment { xsd:integer } + | element ns1:FileUpgradeFlags { empty } + | element ns1:FindInvalidProjectReferences { xsd:boolean } + | element ns1:FriendlyName { xsd:NCName } + | element ns1:GenerateBindingRedirectsOutputType { xsd:boolean } + | element ns1:IISExpressAnonymousAuthentication { empty } + | element ns1:IISExpressSSLPort { text } + | element ns1:IISExpressUseClassicPipelineMode { empty } + | element ns1:IISExpressWindowsAuthentication { empty } + | element ns1:Install { xsd:boolean } + | element ns1:InstallFrom { xsd:NCName } + | element ns1:InstallUrl { empty } + | element ns1:IsCodedUITest { xsd:NCName } + | element ns1:IsWebBootstrapper { xsd:NCName } + | element ns1:LoadBehavior { xsd:integer } + | element ns1:ManifestCertificateThumbprint { text } + | element ns1:ManifestKeyFile { text } + | element ns1:MapFileExtensions { xsd:boolean } + | element ns1:NoStandardLibraries { xsd:boolean } + | element ns1:NoWarn { text } + | element ns1:NuGetPackageImportStamp { empty } + | element ns1:NugetExe { text } + | element ns1:OfficeApplicationDescription { empty } + | element ns1:OldToolsVersion { xsd:decimal } + | element ns1:Optimize { xsd:boolean } + | element ns1:OutputPath { text } + | element ns1:OutputType { xsd:NCName } + | element ns1:PackageDestinationDirectory { text } + | element ns1:Platform { + attribute Condition { text }, + xsd:NCName + } + | element ns1:PlatformTarget { xsd:NCName } + | element ns1:Prefer32Bit { xsd:boolean } + | element ns1:ProductName { xsd:NCName } + | element ns1:ProductVersion { text } + | element ns1:ProjectGuid { text } + | element ns1:ProjectTypeGuids { text } + | element ns1:PublishUrl { text } + | element ns1:PublisherName { empty } + | element ns1:ReferencePath { text } + | element ns1:RestorePackages { xsd:boolean } + | element ns1:RootNamespace { xsd:NCName } + | element ns1:RunPostBuildEvent { xsd:NCName } + | element ns1:SccAuxPath { xsd:anyURI } + | element ns1:SccLocalPath { xsd:NMTOKEN } + | element ns1:SccProjectName { text } + | element ns1:SccProvider { text } + | element ns1:SchemaVersion { xsd:decimal } + | element ns1:SignAssembly { xsd:boolean } + | element ns1:SignManifests { xsd:boolean } + | element ns1:SolutionDir { + attribute Condition { text }, + text + } + | element ns1:StartupObject { empty } + | element ns1:SupportUrl { empty } + | element ns1:TargetCulture { xsd:NCName } + | element ns1:TargetFrameworkProfile { text } + | element ns1:TargetFrameworkVersion { xsd:NCName } + | element ns1:TargetVsixContainerName { xsd:NCName } + | element ns1:TestProjectType { xsd:NCName } + | element ns1:TypeScriptCompileBlocked { xsd:boolean } + | element ns1:TypeScriptToolsVersion { xsd:decimal } + | element ns1:UpdateEnabled { xsd:boolean } + | element ns1:UpdateInterval { xsd:integer } + | element ns1:UpdateIntervalUnits { xsd:NCName } + | element ns1:UpdateMode { xsd:NCName } + | element ns1:UpdatePeriodically { xsd:boolean } + | element ns1:UpdateRequired { xsd:boolean } + | element ns1:UpgradeBackupLocation { empty } + | element ns1:Use64BitIISExpress { empty } + | element ns1:UseApplicationTrust { xsd:boolean } + | element ns1:UseGlobalApplicationHostFile { empty } + | element ns1:UseIISExpress { xsd:boolean } + | element ns1:UseVSHostingProcess { xsd:boolean } + | element ns1:VSTO_TrustAssembliesLocation { xsd:boolean } + | element ns1:VSToolsPath { + attribute Condition { text }, + text + } + | element ns1:VisualStudioVersion { + attribute Condition { text }, + xsd:decimal + } + | element ns1:WarningLevel { xsd:integer } + | element ns1:WcfConfigValidationEnabled { xsd:NCName })*, + element ns1:UseCodebase { xsd:boolean }?, + element ns1:GeneratePkgDefFile { xsd:boolean }?, + (element ns1:CopyBuildOutputToOutputDirectory { xsd:boolean } + | element ns1:CopyOutputSymbolsToOutputDirectory { xsd:boolean } + | element ns1:CopyVsixManifestToOutput { xsd:boolean } + | element ns1:CreateVsixContainer { xsd:boolean } + | element ns1:DeployExtension { xsd:boolean } + | element ns1:DeployVSTemplates { xsd:boolean } + | element ns1:IncludeAssemblyInVSIXContainer { xsd:boolean } + | element ns1:IncludeDebugSymbolsInLocalVSIXDeployment { + xsd:boolean + } + | element ns1:IncludeDebugSymbolsInVSIXContainer { xsd:boolean } + | element ns1:RuntimeIdentifier { xsd:NCName })*, + (element ns1:ApplicationIcon { xsd:NCName } + | element ns1:OfficeApplication { xsd:NCName } + | element ns1:PostBuildEvent { + attribute Condition { text }?, + text + }* + | (element ns1:StartAction { xsd:NCName }, + element ns1:StartProgram { + attribute Condition { text }, + text + }, + element ns1:StartArguments { text }, + element ns1:EnableNoticeInVisualStudioVsix { xsd:boolean })) + } +ns1.ItemGroup = + element ns1:ItemGroup { + (element ns1:AssemblyAttributes { + attribute Include { xsd:NCName }, + element ns1:_Parameter1 { text } + } + | element ns1:COMReference { + attribute Include { xsd:NCName }, + element ns1:Guid { text }, + element ns1:VersionMajor { xsd:integer }, + element ns1:VersionMinor { xsd:integer }, + element ns1:Lcid { xsd:integer }, + element ns1:WrapperTool { xsd:NCName }, + element ns1:Isolated { xsd:NCName }, + ns1.EmbedInteropTypes + } + | element ns1:WCFMetadata { + attribute Include { text } + } + | element ns1:ProjectReference { + attribute Include { text }, + ns1.Project, + element ns1:Name { xsd:NCName }, + (ns1.VSIXSubPath, + element ns1:ReferenceOutputAssembly { xsd:boolean })?, + element ns1:IncludeOutputGroupsInVSIX { text }?, + element ns1:IncludeOutputGroupsInVSIXLocalOnly { text }? + }* + | element ns1:Folder { + attribute Include { text } + }*), + element ns1:VSTemplate { + attribute Include { xsd:NCName }, + element ns1:OutputSubPath { xsd:NCName }?, + ns1.SubType + }*, + (element ns1:CodeAnalysisDependentAssemblyPaths { + attribute Condition { text }, + attribute Include { text }, + element ns1:Visible { xsd:NCName } + } + | element ns1:PackageSourceDirectory { + attribute Include { text } + } + | element ns1:WebReferences { + attribute Include { text } + } + | element ns1:Page { + attribute Include { text }, + ns1.Generator, + ns1.SubType + }* + | element ns1:Reference { + attribute Include { text }, + element ns1:RequiredTargetFramework { xsd:decimal }?, + element ns1:SpecificVersion { xsd:NCName }?, + ns1.EmbedInteropTypes?, + element ns1:HintPath { text }?, + element ns1:Private { xsd:NCName }?, + ns1.Paket? + }* + | element ns1:VSIXSourceItem { + attribute Exclude { text }?, + attribute Include { text }, + attribute VSIXSubPath { xsd:NCName }?, + ns1.VSIXSubPath? + }* + | element ns1:PackageReference { + attribute Include { xsd:NCName }, + attribute Version { text }?, + element ns1:Version { xsd:NMTOKEN }?, + element ns1:IncludeAssets { text }?, + element ns1:PrivateAssets { xsd:NCName }? + }* + | element ns1:Analyzer { + attribute Include { text }, + ns1.Paket + }*), + element ns1:ApplicationDefinition { + attribute Include { xsd:NCName }, + ns1.Generator, + ns1.SubType + }?, + (element ns1:Compile { + attribute Include { text }, + element ns1:AutoGen { xsd:NCName }?, + ns1.Link?, + (ns1.DependentUpon + | element ns1:DesignTime { xsd:NCName } + | element ns1:DesignTimeSharedInput { xsd:NCName })*, + ns1.SubType? + } + | element ns1:Content { + attribute Include { text }, + element ns1:IncludeInVSIX { xsd:boolean }?, + (ns1.CopyToOutputDirectory | ns1.DependentUpon | ns1.SubType)? + } + | element ns1:EmbeddedResource { + attribute Include { text }, + (ns1.Generator, ns1.LastGenOutput)?, + (ns1.DependentUpon | ns1.SubType)? + } + | element ns1:EntityDeploy { + attribute Include { xsd:NCName }, + ns1.Generator, + ns1.LastGenOutput + } + | element ns1:None { + attribute Include { text }, + (ns1.Generator, ns1.LastGenOutput)?, + (ns1.DependentUpon | ns1.Link)?, + ns1.CopyToOutputDirectory?, + ns1.SubType? + } + | element ns1:Resource { + attribute Include { text } + })*, + (element ns1:AppDesigner { + attribute Include { text } + } + | element ns1:Service { + attribute Include { text } + }*) + } +ns1.Output = + element ns1:Output { + attribute ItemName { xsd:NCName }?, + attribute PropertyName { xsd:NCName }?, + attribute TaskParameter { xsd:NCName } + } +EmbedInteropTypes = element EmbedInteropTypes { xsd:NCName } +Generator = element Generator { text } +SubType = element SubType { text } +LastGenOutput = element LastGenOutput { xsd:NCName } +CopyToOutputDirectory = element CopyToOutputDirectory { xsd:NCName } +DependentUpon = element DependentUpon { text } +CopyToPublishDirectory = element CopyToPublishDirectory { xsd:NCName } +Link = element Link { text } +ExcludeFromSingleFile = element ExcludeFromSingleFile { xsd:boolean } +ns1.VSIXSubPath = element ns1:VSIXSubPath { xsd:NCName } +ns1.EmbedInteropTypes = element ns1:EmbedInteropTypes { xsd:NCName } +ns1.SubType = element ns1:SubType { xsd:NCName } +ns1.Generator = element ns1:Generator { xsd:NMTOKEN } +ns1.Paket = element ns1:Paket { xsd:NCName } +ns1.LastGenOutput = element ns1:LastGenOutput { xsd:NCName } +ns1.DependentUpon = element ns1:DependentUpon { xsd:NCName } +ns1.Link = element ns1:Link { text } +ns1.CopyToOutputDirectory = + element ns1:CopyToOutputDirectory { xsd:NCName } diff --git a/etc/schema/nuget.rnc b/etc/schema/nuget.rnc new file mode 100644 index 00000000000..ab7052e91d1 --- /dev/null +++ b/etc/schema/nuget.rnc @@ -0,0 +1,25 @@ +default namespace = "" + +start = + element configuration { + element packageRestore { add+ }?, + (element config { add } + | element packageSourceMapping { + element packageSource { + attribute key { xsd:NCName }, + element package { + attribute pattern { text } + } + }+ + } + | element packageSources { + element clear { empty }, + add+ + })+ + } +add = + element add { + attribute key { xsd:NCName }, + attribute protocolVersion { xsd:integer }?, + attribute value { xsd:anyURI } + } diff --git a/etc/schema/nuspec.rnc b/etc/schema/nuspec.rnc new file mode 100644 index 00000000000..a4332f84fc0 --- /dev/null +++ b/etc/schema/nuspec.rnc @@ -0,0 +1,100 @@ +namespace a = "http://relaxng.org/ns/compatibility/annotations/1.0" +default namespace mstns = "http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd" +namespace rng = "http://relaxng.org/ns/structure/1.0" + +dependency = + attribute id { xsd:string }, + attribute version { xsd:string }?, + attribute include { xsd:string }?, + attribute exclude { xsd:string }? +dependencyGroup = + element dependency { dependency }*, + attribute targetFramework { xsd:string }? +reference = attribute file { xsd:string } +contentFileEntries = + attribute include { xsd:string }, + attribute exclude { xsd:string }?, + attribute buildAction { xsd:string }?, + attribute copyToOutput { xsd:boolean }?, + attribute flatten { xsd:boolean }? +referenceGroup = + element reference { reference }+, + attribute targetFramework { xsd:string }? +frameworkReference = attribute name { xsd:string } +frameworkReferenceGroup = + element frameworkReference { frameworkReference }*, + attribute targetFramework { xsd:string } +start |= starting_package +starting_package = + element package { + element metadata { + (element id { xsd:string } + & element version { xsd:string } + & element title { xsd:string }? + & element authors { xsd:string } + & element owners { xsd:string }? + & element licenseUrl { xsd:anyURI }? + & element projectUrl { xsd:anyURI }? + & element iconUrl { xsd:anyURI }? + & element requireLicenseAcceptance { xsd:boolean }? + & element developmentDependency { xsd:boolean }? + & element description { xsd:string } + & element summary { xsd:string }? + & element releaseNotes { xsd:string }? + & (element copyright { xsd:string }?) + >> a:documentation [ + "\x{a}" ~ + " default value is : en-US" + ] + & element language { xsd:string }? + & element tags { xsd:string }? + & element serviceable { xsd:boolean }? + & element icon { xsd:string }? + & element readme { xsd:string }? + & element repository { + attribute type { xsd:string }?, + attribute url { xsd:anyURI }?, + attribute branch { xsd:string }?, + attribute commit { xsd:string }? + }? + & element license { + xsd:string, + attribute type { xsd:string }, + attribute version { xsd:string }? + }? + & element packageTypes { + element packageType { + attribute name { xsd:string }, + attribute version { xsd:string }? + }* + }? + & element dependencies { + (element dependency { dependency } + | element group { dependencyGroup })* + }? + & element frameworkAssemblies { + element frameworkAssembly { + attribute assemblyName { xsd:string }, + attribute targetFramework { xsd:string }? + }* + }? + & element frameworkReferences { + element group { frameworkReferenceGroup }* + }? + & element references { + (element reference { reference } + | element group { referenceGroup })* + }? + & element contentFiles { + (element files { contentFileEntries })* + }?), + attribute minClientVersion { xsd:string }? + }, + element files { + element file { + attribute src { xsd:string }, + attribute target { xsd:string }?, + attribute exclude { xsd:string }? + }* + }? + } diff --git a/etc/schema/schemas.xml b/etc/schema/schemas.xml index f04bba849b4..be0dacd6ecf 100644 --- a/etc/schema/schemas.xml +++ b/etc/schema/schemas.xml @@ -66,4 +66,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + commit bffa00bcbcf027e152b7cdd4cbcadfd600f87ea9 Author: Stefan Kangas Date: Sat May 18 20:33:16 2024 +0200 ; Fix typo (Bug#71043) diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index 1d94b1c6253..1bc0acfacd0 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -774,7 +774,7 @@ symbol or thing definition (@pxref{User-defined Things}). Using an undefined thing doesn't raise an error, the function simply returns @code{nil}. -This function returns the first node that matches, or @code{nil} if node +This function returns the first node that matches, or @code{nil} if none matches @var{predicate}. By default, this function only traverses named nodes, but if @var{all} commit 96f64c156c6b76ba02232179ad76ace04a92ed06 Author: Stefan Kangas Date: Sat May 18 19:23:11 2024 +0200 Fix double periods in `doctor-symptoms` * lisp/play/doctor.el (doctor-symptoms): Don't produce double periods. diff --git a/lisp/play/doctor.el b/lisp/play/doctor.el index 79ddc4fc929..4f18ae14f23 100644 --- a/lisp/play/doctor.el +++ b/lisp/play/doctor.el @@ -1522,7 +1522,7 @@ Hack on previous word, setting global variable DOCTOR-OWNER to correct result." (defun doctor-symptoms () (doctor-type '((doc$ doctor--maybe) you should consult a medical doctor\; - i am a psychotherapist. \.))) + i am a psychotherapist \.))) (defun doctor-hates () (doctor-svo doctor-sent doctor-found 1 t) commit 21ed391440ec9c227f3d18cc222aab2d3d0f9e14 Author: Paul Eggert Date: Sun May 12 14:26:32 2024 -0700 Simplify 32-bit Android bit fiddling * src/sfnt.c: Include stdbit.h. (sfnt_count_leading_zero_bits) [!INT64_MAX]: Remove this function, which was confusingly named as it actually returned 31 minus the number of leading zero bits. (sfnt_multiply_divide_2) [!INT64_MAX]: Use stdc_leading_zeros instead. diff --git a/src/sfnt.c b/src/sfnt.c index d909fba7677..1832082e4f9 100644 --- a/src/sfnt.c +++ b/src/sfnt.c @@ -27,6 +27,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -3678,45 +3679,6 @@ sfnt_multiply_divide_1 (unsigned int a, unsigned int b, value->high = hi; } -/* Count the number of most significant zero bits in N. */ - -static unsigned int -sfnt_count_leading_zero_bits (unsigned int n) -{ - int shift; - - shift = 0; - - if (n & 0xffff0000ul) - { - n >>= 16; - shift += 16; - } - - if (n & 0x0000ff00ul) - { - n >>= 8; - shift += 8; - } - - if (n & 0x000000f0ul) - { - n >>= 4; - shift += 4; - } - - if (n & 0x0000000cul) - { - n >>= 2; - shift += 2; - } - - if (n & 0x00000002ul) - shift += 1; - - return shift; -} - /* Calculate AB / C. Value is a 32 bit unsigned integer. */ static unsigned int @@ -3730,7 +3692,7 @@ sfnt_multiply_divide_2 (struct sfnt_large_integer *ab, hi = ab->high; lo = ab->low; - i = 31 - sfnt_count_leading_zero_bits (hi); + i = stdc_leading_zeros (hi); r = (hi << i) | (lo >> (32 - i)); lo <<= i; q = r / c; commit 88b0bb4db9aaecff8b01e81726b911fa5d02b2fb Author: Paul Eggert Date: Sun May 12 14:22:58 2024 -0700 Prefer stdbit.h to count-one-bits.h etc C23's in the long run should be better supported than Gnulib's count-one-bits.h and similar headers, so switch to the C23 primitives, with a Gnulib fallback for platforms lacking C23. * admin/merge-gnulib (GNULIB_MODULES): Remove count-leading-zeros, count-one-bits, count-trailing-zeros. Add stdc_bit_width, stdc_count_ones, stdc_trailing_zeros. * lib/count-leading-zeros.c, lib/count-leading-zeros.h: * lib/count-one-bits.c, lib/count-one-bits.h: * lib/count-trailing-zeros.c, lib/count-trailing-zeros.h: Remove. * lib/stdbit.c, lib/stdbit.in.h, lib/stdc_bit_width.c: * lib/stdc_count_ones.c, lib/stdc_leading_zeros.c: * lib/stdc_trailing_zeros.c, m4/stdbit_h.m4: New files, copied from Gnulib. * lib/gnulib.mk.in, m4/gnulib-comp.m4: Regenerate. * src/data.c: Do not include count-one-bits.h, count-trailing-zeros.h. Instead, rely on lisp.h including stdbit.h. (Flogcount, Fbool_vector_count_population) (Fbool_vector_count_consecutive): Use stdbit.h macros instead of count-one-bits.h and count-trailing-zeros.h macros. (shift_right_ull, count_one_bits_word, pre_value) (count_trailing_zero_bits): Remove; no longer needed. * src/lisp.h: Include stdbit.h instead of count-leading-zeros.h. (elogb): Use stdbit.h macro instead of count-leading-zeros.h macro. diff --git a/INSTALL.REPO b/INSTALL.REPO index 77d8153a5a8..46ac4440aee 100644 --- a/INSTALL.REPO +++ b/INSTALL.REPO @@ -80,7 +80,7 @@ handle. The most thorough cleaning can be achieved by 'git clean -fdx' which will leave you with only files from the git repository. Here are some faster methods for a couple of particular error cases: - /usr/bin/m4:aclocal.m4:9: cannot open `m4/count-leading-zeros.m4': No such file or directory + /usr/bin/m4:aclocal.m4:9: cannot open `m4/stdbit_h.m4': No such file or directory This can be fixed with 'rm aclocal.m4'. diff --git a/admin/merge-gnulib b/admin/merge-gnulib index c4daaded015..65e098c7123 100755 --- a/admin/merge-gnulib +++ b/admin/merge-gnulib @@ -29,7 +29,6 @@ GNULIB_MODULES=' alignasof alloca-opt binary-io boot-time byteswap c-ctype c-strcase canonicalize-lgpl careadlinkat close-stream copy-file-range - count-leading-zeros count-one-bits count-trailing-zeros crypto/md5 crypto/md5-buffer crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer d-type diffseq double-slash-root dtoastr dtotimespec dup2 @@ -44,7 +43,9 @@ GNULIB_MODULES=' nanosleep nproc nstrftime pathmax pipe2 pselect pthread_sigmask qcopy-acl readlink readlinkat regex - sig2str sigdescr_np socklen stat-time std-gnu11 stdbool stdckdint stddef stdio + sig2str sigdescr_np socklen stat-time std-gnu11 stdbool + stdc_bit_width stdc_count_ones stdc_trailing_zeros + stdckdint stddef stdio stpcpy strnlen strnlen strtoimax symlink sys_stat sys_time tempname time-h time_r time_rz timegm timer-time timespec-add timespec-sub update-copyright unlocked-io utimensat diff --git a/lib/count-leading-zeros.h b/lib/count-leading-zeros.h deleted file mode 100644 index a4b68c21064..00000000000 --- a/lib/count-leading-zeros.h +++ /dev/null @@ -1,140 +0,0 @@ -/* count-leading-zeros.h -- counts the number of leading 0 bits in a word. - Copyright (C) 2012-2024 Free Software Foundation, Inc. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* Written by Eric Blake. */ - -#ifndef COUNT_LEADING_ZEROS_H -#define COUNT_LEADING_ZEROS_H 1 - -/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include -#include - -_GL_INLINE_HEADER_BEGIN -#ifndef COUNT_LEADING_ZEROS_INLINE -# define COUNT_LEADING_ZEROS_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN, - expand to code that computes the number of leading zeros of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \ - || (__clang_major__ >= 4) -# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - return x ? BUILTIN (x) : CHAR_BIT * sizeof x; -#elif _MSC_VER -extern unsigned char _BitScanReverse (unsigned long *, unsigned long); -# pragma intrinsic (_BitScanReverse) -# if defined _M_X64 -extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long); -# pragma intrinsic (_BitScanReverse64) -# endif -# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - unsigned long result; \ - if (MSC_BUILTIN (&result, x)) \ - return CHAR_BIT * sizeof x - 1 - result; \ - return CHAR_BIT * sizeof x; \ - } \ - while (0) -#else -# define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - int count; \ - unsigned int leading_32; \ - if (! x) \ - return CHAR_BIT * sizeof x; \ - for (count = 0; \ - (leading_32 = ((x >> (sizeof (TYPE) * CHAR_BIT - 32)) \ - & 0xffffffffU), \ - count < CHAR_BIT * sizeof x - 32 && !leading_32); \ - count += 32) \ - x = x << 31 << 1; \ - return count + count_leading_zeros_32 (leading_32); \ - } \ - while (0) - -/* Compute and return the number of leading zeros in X, - where 0 < X < 2**32. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros_32 (unsigned int x) -{ - /* - */ - static const char de_Bruijn_lookup[32] = { - 31, 22, 30, 21, 18, 10, 29, 2, 20, 17, 15, 13, 9, 6, 28, 1, - 23, 19, 11, 3, 16, 14, 7, 24, 12, 4, 8, 25, 5, 26, 27, 0 - }; - - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return de_Bruijn_lookup[((x * 0x07c4acddU) & 0xffffffffU) >> 27]; -} -#endif - -/* Compute and return the number of leading zeros in X. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros (unsigned int x) -{ - COUNT_LEADING_ZEROS (__builtin_clz, _BitScanReverse, unsigned int); -} - -/* Compute and return the number of leading zeros in X. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros_l (unsigned long int x) -{ - COUNT_LEADING_ZEROS (__builtin_clzl, _BitScanReverse, unsigned long int); -} - -/* Compute and return the number of leading zeros in X. */ -COUNT_LEADING_ZEROS_INLINE int -count_leading_zeros_ll (unsigned long long int x) -{ -#if (defined _MSC_VER && !defined __clang__) && !defined _M_X64 - /* 32-bit MSVC does not have _BitScanReverse64, only _BitScanReverse. */ - unsigned long result; - if (_BitScanReverse (&result, (unsigned long) (x >> 32))) - return CHAR_BIT * sizeof x - 1 - 32 - result; - if (_BitScanReverse (&result, (unsigned long) x)) - return CHAR_BIT * sizeof x - 1 - result; - return CHAR_BIT * sizeof x; -#else - COUNT_LEADING_ZEROS (__builtin_clzll, _BitScanReverse64, - unsigned long long int); -#endif -} - -#ifdef __cplusplus -} -#endif - -_GL_INLINE_HEADER_END - -#endif /* COUNT_LEADING_ZEROS_H */ diff --git a/lib/count-one-bits.h b/lib/count-one-bits.h deleted file mode 100644 index 24bf8cc2327..00000000000 --- a/lib/count-one-bits.h +++ /dev/null @@ -1,169 +0,0 @@ -/* count-one-bits.h -- counts the number of 1-bits in a word. - Copyright (C) 2007-2024 Free Software Foundation, Inc. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* Written by Ben Pfaff. */ - -#ifndef COUNT_ONE_BITS_H -#define COUNT_ONE_BITS_H 1 - -/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include -#include - -_GL_INLINE_HEADER_BEGIN -#ifndef COUNT_ONE_BITS_INLINE -# define COUNT_ONE_BITS_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Assuming the GCC builtin is GCC_BUILTIN and the MSC builtin is MSC_BUILTIN, - expand to code that computes the number of 1-bits of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \ - || (__clang_major__ >= 4) -# define COUNT_ONE_BITS(GCC_BUILTIN, MSC_BUILTIN, TYPE) \ - return GCC_BUILTIN (x) -#else - -/* Compute and return the number of 1-bits set in the least - significant 32 bits of X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits_32 (unsigned int x) -{ - x = ((x & 0xaaaaaaaaU) >> 1) + (x & 0x55555555U); - x = ((x & 0xccccccccU) >> 2) + (x & 0x33333333U); - x = (x >> 16) + (x & 0xffff); - x = ((x & 0xf0f0) >> 4) + (x & 0x0f0f); - return (x >> 8) + (x & 0x00ff); -} - -/* Expand to code that computes the number of 1-bits of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -# define COUNT_ONE_BITS_GENERIC(TYPE) \ - do \ - { \ - int count = 0; \ - int bits; \ - for (bits = 0; bits < sizeof (TYPE) * CHAR_BIT; bits += 32) \ - { \ - count += count_one_bits_32 (x); \ - x = x >> 31 >> 1; \ - } \ - return count; \ - } \ - while (0) - -# if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) - -/* While gcc falls back to its own generic code if the machine - on which it's running doesn't support popcount, with Microsoft's - compiler we need to detect and fallback ourselves. */ - -# if 0 -# include -# else - /* Don't pollute the namespace with too many MSVC intrinsics. */ -extern void __cpuid (int[4], int); -# pragma intrinsic (__cpuid) -extern unsigned int __popcnt (unsigned int); -# pragma intrinsic (__popcnt) -# if defined _M_X64 -extern unsigned long long __popcnt64 (unsigned long long); -# pragma intrinsic (__popcnt64) -# endif -# endif - -# if !defined _M_X64 -static inline __popcnt64 (unsigned long long x) -{ - return __popcnt ((unsigned int) (x >> 32)) + __popcnt ((unsigned int) x); -} -# endif - -/* Return nonzero if popcount is supported. */ - -/* 1 if supported, 0 if not supported, -1 if unknown. */ -extern int popcount_support; - -COUNT_ONE_BITS_INLINE int -popcount_supported (void) -{ - if (popcount_support < 0) - { - /* Do as described in - */ - int cpu_info[4]; - __cpuid (cpu_info, 1); - popcount_support = (cpu_info[2] >> 23) & 1; - } - return popcount_support; -} - -# define COUNT_ONE_BITS(GCC_BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - if (popcount_supported ()) \ - return MSC_BUILTIN (x); \ - else \ - COUNT_ONE_BITS_GENERIC (TYPE); \ - } \ - while (0) - -# else - -# define COUNT_ONE_BITS(GCC_BUILTIN, MSC_BUILTIN, TYPE) \ - COUNT_ONE_BITS_GENERIC (TYPE) - -# endif -#endif - -/* Compute and return the number of 1-bits set in X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits (unsigned int x) -{ - COUNT_ONE_BITS (__builtin_popcount, __popcnt, unsigned int); -} - -/* Compute and return the number of 1-bits set in X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits_l (unsigned long int x) -{ - COUNT_ONE_BITS (__builtin_popcountl, __popcnt, unsigned long int); -} - -/* Compute and return the number of 1-bits set in X. */ -COUNT_ONE_BITS_INLINE int -count_one_bits_ll (unsigned long long int x) -{ - COUNT_ONE_BITS (__builtin_popcountll, __popcnt64, unsigned long long int); -} - -#ifdef __cplusplus -} -#endif - -_GL_INLINE_HEADER_END - -#endif /* COUNT_ONE_BITS_H */ diff --git a/lib/count-trailing-zeros.h b/lib/count-trailing-zeros.h deleted file mode 100644 index 82de8731ec1..00000000000 --- a/lib/count-trailing-zeros.h +++ /dev/null @@ -1,130 +0,0 @@ -/* count-trailing-zeros.h -- counts the number of trailing 0 bits in a word. - Copyright 2013-2024 Free Software Foundation, Inc. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see . */ - -/* Written by Paul Eggert. */ - -#ifndef COUNT_TRAILING_ZEROS_H -#define COUNT_TRAILING_ZEROS_H 1 - -/* This file uses _GL_INLINE_HEADER_BEGIN, _GL_INLINE. */ -#if !_GL_CONFIG_H_INCLUDED - #error "Please include config.h first." -#endif - -#include -#include - -_GL_INLINE_HEADER_BEGIN -#ifndef COUNT_TRAILING_ZEROS_INLINE -# define COUNT_TRAILING_ZEROS_INLINE _GL_INLINE -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* Assuming the GCC builtin is BUILTIN and the MSC builtin is MSC_BUILTIN, - expand to code that computes the number of trailing zeros of the local - variable 'x' of type TYPE (an unsigned integer type) and return it - from the current function. */ -#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \ - || (__clang_major__ >= 4) -# define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - return x ? BUILTIN (x) : CHAR_BIT * sizeof x; -#elif _MSC_VER -extern unsigned char _BitScanForward (unsigned long *, unsigned long); -# pragma intrinsic (_BitScanForward) -# if defined _M_X64 -extern unsigned char _BitScanForward64 (unsigned long *, unsigned long long); -# pragma intrinsic (_BitScanForward64) -# endif -# define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - unsigned long result; \ - return MSC_BUILTIN (&result, x) ? result : CHAR_BIT * sizeof x; \ - } \ - while (0) -#else -# define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ - do \ - { \ - int count = 0; \ - if (! x) \ - return CHAR_BIT * sizeof x; \ - for (count = 0; \ - (count < CHAR_BIT * sizeof x - 32 \ - && ! (x & 0xffffffffU)); \ - count += 32) \ - x = x >> 31 >> 1; \ - return count + count_trailing_zeros_32 (x); \ - } \ - while (0) - -/* Compute and return the number of trailing zeros in the least - significant 32 bits of X. One of these bits must be nonzero. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros_32 (unsigned int x) -{ - /* - */ - static const char de_Bruijn_lookup[32] = { - 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, - 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 - }; - return de_Bruijn_lookup[(((x & -x) * 0x077cb531U) & 0xffffffffU) >> 27]; -} -#endif - -/* Compute and return the number of trailing zeros in X. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros (unsigned int x) -{ - COUNT_TRAILING_ZEROS (__builtin_ctz, _BitScanForward, unsigned int); -} - -/* Compute and return the number of trailing zeros in X. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros_l (unsigned long int x) -{ - COUNT_TRAILING_ZEROS (__builtin_ctzl, _BitScanForward, unsigned long int); -} - -/* Compute and return the number of trailing zeros in X. */ -COUNT_TRAILING_ZEROS_INLINE int -count_trailing_zeros_ll (unsigned long long int x) -{ -#if (defined _MSC_VER && !defined __clang__) && !defined _M_X64 - /* 32-bit MSVC does not have _BitScanForward64, only _BitScanForward. */ - unsigned long result; - if (_BitScanForward (&result, (unsigned long) x)) - return result; - if (_BitScanForward (&result, (unsigned long) (x >> 32))) - return result + 32; - return CHAR_BIT * sizeof x; -#else - COUNT_TRAILING_ZEROS (__builtin_ctzll, _BitScanForward64, - unsigned long long int); -#endif -} - -#ifdef __cplusplus -} -#endif - -_GL_INLINE_HEADER_END - -#endif diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index d03e193b63c..358d58d5015 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -86,9 +86,6 @@ # careadlinkat \ # close-stream \ # copy-file-range \ -# count-leading-zeros \ -# count-one-bits \ -# count-trailing-zeros \ # crypto/md5 \ # crypto/md5-buffer \ # crypto/sha1-buffer \ @@ -156,6 +153,9 @@ # stat-time \ # std-gnu11 \ # stdbool \ +# stdc_bit_width \ +# stdc_count_ones \ +# stdc_trailing_zeros \ # stdckdint \ # stddef \ # stdio \ @@ -358,6 +358,7 @@ GL_GENERATE_GMP_H_CONDITION = @GL_GENERATE_GMP_H_CONDITION@ GL_GENERATE_IEEE754_H_CONDITION = @GL_GENERATE_IEEE754_H_CONDITION@ GL_GENERATE_LIMITS_H_CONDITION = @GL_GENERATE_LIMITS_H_CONDITION@ GL_GENERATE_MINI_GMP_H_CONDITION = @GL_GENERATE_MINI_GMP_H_CONDITION@ +GL_GENERATE_STDBIT_H_CONDITION = @GL_GENERATE_STDBIT_H_CONDITION@ GL_GENERATE_STDCKDINT_H_CONDITION = @GL_GENERATE_STDCKDINT_H_CONDITION@ GL_GENERATE_STDDEF_H_CONDITION = @GL_GENERATE_STDDEF_H_CONDITION@ GL_GENERATE_STDINT_H_CONDITION = @GL_GENERATE_STDINT_H_CONDITION@ @@ -664,6 +665,20 @@ GL_GNULIB_VSPRINTF_POSIX = @GL_GNULIB_VSPRINTF_POSIX@ GL_GNULIB_WCTOMB = @GL_GNULIB_WCTOMB@ GL_GNULIB_WRITE = @GL_GNULIB_WRITE@ GL_GNULIB__EXIT = @GL_GNULIB__EXIT@ +GL_STDC_BIT_CEIL = @GL_STDC_BIT_CEIL@ +GL_STDC_BIT_FLOOR = @GL_STDC_BIT_FLOOR@ +GL_STDC_BIT_WIDTH = @GL_STDC_BIT_WIDTH@ +GL_STDC_COUNT_ONES = @GL_STDC_COUNT_ONES@ +GL_STDC_COUNT_ZEROS = @GL_STDC_COUNT_ZEROS@ +GL_STDC_FIRST_LEADING_ONE = @GL_STDC_FIRST_LEADING_ONE@ +GL_STDC_FIRST_LEADING_ZERO = @GL_STDC_FIRST_LEADING_ZERO@ +GL_STDC_FIRST_TRAILING_ONE = @GL_STDC_FIRST_TRAILING_ONE@ +GL_STDC_FIRST_TRAILING_ZERO = @GL_STDC_FIRST_TRAILING_ZERO@ +GL_STDC_HAS_SINGLE_BIT = @GL_STDC_HAS_SINGLE_BIT@ +GL_STDC_LEADING_ONES = @GL_STDC_LEADING_ONES@ +GL_STDC_LEADING_ZEROS = @GL_STDC_LEADING_ZEROS@ +GL_STDC_TRAILING_ONES = @GL_STDC_TRAILING_ONES@ +GL_STDC_TRAILING_ZEROS = @GL_STDC_TRAILING_ZEROS@ GMALLOC_OBJ = @GMALLOC_OBJ@ GMP_H = @GMP_H@ GNULIBHEADERS_OVERRIDE_WINT_T = @GNULIBHEADERS_OVERRIDE_WINT_T@ @@ -1315,6 +1330,7 @@ SIZE_T_SUFFIX = @SIZE_T_SUFFIX@ SMALL_JA_DIC = @SMALL_JA_DIC@ SQLITE3_CFLAGS = @SQLITE3_CFLAGS@ SQLITE3_LIBS = @SQLITE3_LIBS@ +STDBIT_H = @STDBIT_H@ STDCKDINT_H = @STDCKDINT_H@ STDDEF_H = @STDDEF_H@ STDDEF_NOT_IDEMPOTENT = @STDDEF_NOT_IDEMPOTENT@ @@ -1444,6 +1460,7 @@ gl_GNULIB_ENABLED_open_CONDITION = @gl_GNULIB_ENABLED_open_CONDITION@ gl_GNULIB_ENABLED_rawmemchr_CONDITION = @gl_GNULIB_ENABLED_rawmemchr_CONDITION@ gl_GNULIB_ENABLED_strtoll_CONDITION = @gl_GNULIB_ENABLED_strtoll_CONDITION@ gl_GNULIB_ENABLED_utimens_CONDITION = @gl_GNULIB_ENABLED_utimens_CONDITION@ +gl_GNULIB_ENABLED_verify_CONDITION = @gl_GNULIB_ENABLED_verify_CONDITION@ gl_LIBOBJDEPS = @gl_LIBOBJDEPS@ gl_LIBOBJS = @gl_LIBOBJS@ gl_LTLIBOBJS = @gl_LTLIBOBJS@ @@ -1721,36 +1738,6 @@ endif endif ## end gnulib module copy-file-range -## begin gnulib module count-leading-zeros -ifeq (,$(OMIT_GNULIB_MODULE_count-leading-zeros)) - -libgnu_a_SOURCES += count-leading-zeros.c - -EXTRA_DIST += count-leading-zeros.h - -endif -## end gnulib module count-leading-zeros - -## begin gnulib module count-one-bits -ifeq (,$(OMIT_GNULIB_MODULE_count-one-bits)) - -libgnu_a_SOURCES += count-one-bits.c - -EXTRA_DIST += count-one-bits.h - -endif -## end gnulib module count-one-bits - -## begin gnulib module count-trailing-zeros -ifeq (,$(OMIT_GNULIB_MODULE_count-trailing-zeros)) - -libgnu_a_SOURCES += count-trailing-zeros.c - -EXTRA_DIST += count-trailing-zeros.h - -endif -## end gnulib module count-trailing-zeros - ## begin gnulib module crypto/md5 ifeq (,$(OMIT_GNULIB_MODULE_crypto/md5)) @@ -3052,6 +3039,84 @@ EXTRA_DIST += stat-time.h endif ## end gnulib module stat-time +## begin gnulib module stdbit-h +ifeq (,$(OMIT_GNULIB_MODULE_stdbit-h)) + +BUILT_SOURCES += $(STDBIT_H) + +# We need the following in order to create when the system +# doesn't have one that works with the given compiler. +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +stdbit.h: stdbit.in.h $(top_builddir)/config.status + $(gl_V_at)$(SED_HEADER_STDOUT) \ + -e 's/@''GL_STDC_LEADING_ZEROS''@/$(GL_STDC_LEADING_ZEROS)/g' \ + -e 's/@''GL_STDC_LEADING_ONES''@/$(GL_STDC_LEADING_ONES)/g' \ + -e 's/@''GL_STDC_TRAILING_ZEROS''@/$(GL_STDC_TRAILING_ZEROS)/g' \ + -e 's/@''GL_STDC_TRAILING_ONES''@/$(GL_STDC_TRAILING_ONES)/g' \ + -e 's/@''GL_STDC_FIRST_LEADING_ZERO''@/$(GL_STDC_FIRST_LEADING_ZERO)/g' \ + -e 's/@''GL_STDC_FIRST_LEADING_ONE''@/$(GL_STDC_FIRST_LEADING_ONE)/g' \ + -e 's/@''GL_STDC_FIRST_TRAILING_ZERO''@/$(GL_STDC_FIRST_TRAILING_ZERO)/g' \ + -e 's/@''GL_STDC_FIRST_TRAILING_ONE''@/$(GL_STDC_FIRST_TRAILING_ONE)/g' \ + -e 's/@''GL_STDC_COUNT_ZEROS''@/$(GL_STDC_COUNT_ZEROS)/g' \ + -e 's/@''GL_STDC_COUNT_ONES''@/$(GL_STDC_COUNT_ONES)/g' \ + -e 's/@''GL_STDC_HAS_SINGLE_BIT''@/$(GL_STDC_HAS_SINGLE_BIT)/g' \ + -e 's/@''GL_STDC_BIT_WIDTH''@/$(GL_STDC_BIT_WIDTH)/g' \ + -e 's/@''GL_STDC_BIT_FLOOR''@/$(GL_STDC_BIT_FLOOR)/g' \ + -e 's/@''GL_STDC_BIT_CEIL''@/$(GL_STDC_BIT_CEIL)/g' \ + $(srcdir)/stdbit.in.h > $@-t + $(AM_V_at)mv $@-t $@ +libgnu_a_SOURCES += stdbit.c +else +stdbit.h: $(top_builddir)/config.status + rm -f $@ +endif +MOSTLYCLEANFILES += stdbit.h stdbit.h-t + +EXTRA_DIST += stdbit.in.h + +endif +## end gnulib module stdbit-h + +## begin gnulib module stdc_bit_width +ifeq (,$(OMIT_GNULIB_MODULE_stdc_bit_width)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_bit_width.c +endif + +endif +## end gnulib module stdc_bit_width + +## begin gnulib module stdc_count_ones +ifeq (,$(OMIT_GNULIB_MODULE_stdc_count_ones)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_count_ones.c +endif + +endif +## end gnulib module stdc_count_ones + +## begin gnulib module stdc_leading_zeros +ifeq (,$(OMIT_GNULIB_MODULE_stdc_leading_zeros)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_leading_zeros.c +endif + +endif +## end gnulib module stdc_leading_zeros + +## begin gnulib module stdc_trailing_zeros +ifeq (,$(OMIT_GNULIB_MODULE_stdc_trailing_zeros)) + +ifneq (,$(GL_GENERATE_STDBIT_H_CONDITION)) +libgnu_a_SOURCES += stdc_trailing_zeros.c +endif + +endif +## end gnulib module stdc_trailing_zeros + ## begin gnulib module stdckdint ifeq (,$(OMIT_GNULIB_MODULE_stdckdint)) @@ -4274,7 +4339,9 @@ endif ## begin gnulib module verify ifeq (,$(OMIT_GNULIB_MODULE_verify)) +ifneq (,$(gl_GNULIB_ENABLED_verify_CONDITION)) +endif EXTRA_DIST += verify.h endif diff --git a/lib/stdbit.c b/lib/stdbit.c new file mode 100644 index 00000000000..4801e74d281 --- /dev/null +++ b/lib/stdbit.c @@ -0,0 +1,23 @@ +/* Support C23 bit and byte utilities on non-C23 platforms. + + Copyright 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#include + +#define _GL_STDBIT_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/stdbit.in.h b/lib/stdbit.in.h new file mode 100644 index 00000000000..9f9e60a5d38 --- /dev/null +++ b/lib/stdbit.in.h @@ -0,0 +1,1077 @@ +/* stdbit.h - C23 bit and byte utilities for non-C23 platforms + + Copyright 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +/* Written by Paul Eggert. */ + +#ifndef STDBIT_H +#define STDBIT_H 1 + +/* This file uses _GL_INLINE, WORDS_BIGENDIAN. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + +_GL_INLINE_HEADER_BEGIN + +#ifndef _GL_STDBIT_INLINE +# define _GL_STDBIT_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_LEADING_ZEROS_INLINE +# define _GL_STDC_LEADING_ZEROS_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_LEADING_ONES_INLINE +# define _GL_STDC_LEADING_ONES_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_TRAILING_ZEROS_INLINE +# define _GL_STDC_TRAILING_ZEROS_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_TRAILING_ONES_INLINE +# define _GL_STDC_TRAILING_ONES_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_LEADING_ZERO_INLINE +# define _GL_STDC_FIRST_LEADING_ZERO_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_LEADING_ONE_INLINE +# define _GL_STDC_FIRST_LEADING_ONE_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_TRAILING_ZERO_INLINE +# define _GL_STDC_FIRST_TRAILING_ZERO_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_FIRST_TRAILING_ONE_INLINE +# define _GL_STDC_FIRST_TRAILING_ONE_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_COUNT_ZEROS_INLINE +# define _GL_STDC_COUNT_ZEROS_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_COUNT_ONES_INLINE +# define _GL_STDC_COUNT_ONES_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_HAS_SINGLE_BIT_INLINE +# define _GL_STDC_HAS_SINGLE_BIT_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_BIT_WIDTH_INLINE +# define _GL_STDC_BIT_WIDTH_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_BIT_FLOOR_INLINE +# define _GL_STDC_BIT_FLOOR_INLINE _GL_INLINE +#endif +#ifndef _GL_STDC_BIT_CEIL_INLINE +# define _GL_STDC_BIT_CEIL_INLINE _GL_INLINE +#endif + +/* An expression, preferably with the type of A, that has the value of B. */ +#if ((defined __GNUC__ && 2 <= __GNUC__) \ + || (defined __clang_major__ && 4 <= __clang_major__) \ + || (defined __IBMC__ && 1210 <= __IBMC__ && defined __IBM__TYPEOF__) \ + || (defined __SUNPRO_C && 0x5110 <= __SUNPRO_C && !__STDC__)) +# define _GL_STDBIT_TYPEOF_CAST(a, b) ((__typeof__ (a)) (b)) +#elif 202311 <= __STDC_VERSION__ +# define _GL_STDBIT_TYPEOF_CAST(a, b) ((typeof (a)) (b)) +#else +/* This platform is so old that it lacks typeof, so _Generic is likely + missing or unreliable. The C23 standard seems to allow yielding B + (which is always unsigned long long int), so do that. */ +# define _GL_STDBIT_TYPEOF_CAST(a, b) (b) +#endif + + +/* ISO C 23 § 7.18.1 General */ + +#define __STDC_VERSION_STDBIT_H__ 202311L + + +/* ISO C 23 § 7.18.2 Endian */ + +#define __STDC_ENDIAN_BIG__ 4321 +#define __STDC_ENDIAN_LITTLE__ 1234 +#ifdef WORDS_BIGENDIAN +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_BIG__ +#else +# define __STDC_ENDIAN_NATIVE__ __STDC_ENDIAN_LITTLE__ +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +#if 3 < __GNUC__ + (4 <= __GNUC_MINOR__) || 4 <= __clang_major__ +# define _GL_STDBIT_HAS_BUILTIN_CLZ true +# define _GL_STDBIT_HAS_BUILTIN_CTZ true +# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true +#elif defined __has_builtin +# if (__has_builtin (__builtin_clz) \ + && __has_builtin (__builtin_clzl) \ + && __has_builtin (__builtin_clzll)) +# define _GL_STDBIT_HAS_BUILTIN_CLZ true +# endif +# if (__has_builtin (__builtin_ctz) \ + && __has_builtin (__builtin_ctzl) \ + && __has_builtin (__builtin_ctzll)) +# define _GL_STDBIT_HAS_BUILTIN_CTZ true +# endif +# if (__has_builtin (__builtin_popcount) \ + && __has_builtin (__builtin_popcountl) \ + && __has_builtin (__builtin_popcountll)) +# define _GL_STDBIT_HAS_BUILTIN_POPCOUNT true +# endif +#endif + +/* Count leading 0 bits of N, even if N is 0. */ +#ifdef _GL_STDBIT_HAS_BUILTIN_CLZ +_GL_STDBIT_INLINE int +__gl_stdbit_clz (unsigned int n) +{ + return n ? __builtin_clz (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzl (unsigned long int n) +{ + return n ? __builtin_clzl (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzll (unsigned long long int n) +{ + return n ? __builtin_clzll (n) : 8 * sizeof n; +} +#elif defined _MSC_VER + +/* Declare the few MSVC intrinsics that we need. We prefer not to include + because it would pollute the namespace. */ +extern unsigned char _BitScanReverse (unsigned long *, unsigned long); +# pragma intrinsic (_BitScanReverse) +# ifdef _M_X64 +extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long); +# pragma intrinsic (_BitScanReverse64) +# endif + +_GL_STDBIT_INLINE int +__gl_stdbit_clzl (unsigned long int n) +{ + unsigned long int r; + return 8 * sizeof n - (_BitScanReverse (&r, n) ? r + 1 : 0); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clz (unsigned int n) +{ + return __gl_stdbit_clzl (n) - 8 * (sizeof 0ul - sizeof n); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzll (unsigned long long int n) +{ +# ifdef _M_X64 + unsigned long int r; + return 8 * sizeof n - (_BitScanReverse64 (&r, n) ? r + 1 : 0); +# else + unsigned long int hi = n >> 32; + return __gl_stdbit_clzl (hi ? hi : n) + (hi ? 0 : 32); +# endif +} + +#else /* !_MSC_VER */ + +_GL_STDBIT_INLINE int +__gl_stdbit_clzll (unsigned long long int n) +{ + int r = 0; + for (int i = 8 * sizeof n >> 1; 1 << 6 <= i; i >>= 1) + { + int a = (1ull << i <= n) * i; n >>= a; r += a; + } + int a5 = (0x00000000ffffffff < n) << 5; n >>= a5; r += a5; + int a4 = (0x000000000000ffff < n) << 4; n >>= a4; r += a4; + int a3 = (0x00000000000000ff < n) << 3; n >>= a3; r += a3; + int a2 = (0x000000000000000f < n) << 2; n >>= a2; r += a2; + return (8 * sizeof n - (1 << 2) - r) + ((0x11112234ull >> (n << 2)) & 0xf); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clz (unsigned int n) +{ + return __gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0u); +} +_GL_STDBIT_INLINE int +__gl_stdbit_clzl (unsigned long int n) +{ + return __gl_stdbit_clzll (n) - 8 * (sizeof 0ull - sizeof 0ul); +} +#endif + +/* Count trailing 0 bits of N, even if N is 0. */ +#ifdef _GL_STDBIT_HAS_BUILTIN_CTZ +_GL_STDBIT_INLINE int +__gl_stdbit_ctz (unsigned int n) +{ + return n ? __builtin_ctz (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzl (unsigned long int n) +{ + return n ? __builtin_ctzl (n) : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzll (unsigned long long int n) +{ + return n ? __builtin_ctzll (n) : 8 * sizeof n; +} +#elif defined _MSC_VER + +/* Declare the few MSVC intrinsics that we need. We prefer not to include + because it would pollute the namespace. */ +extern unsigned char _BitScanForward (unsigned long *, unsigned long); +# pragma intrinsic (_BitScanForward) +# ifdef _M_X64 +extern unsigned char _BitScanForward64 (unsigned long *, unsigned long long); +# pragma intrinsic (_BitScanForward64) +# endif + +_GL_STDBIT_INLINE int +__gl_stdbit_ctzl (unsigned long int n) +{ + unsigned long int r; + return _BitScanForward (&r, n) ? r : 8 * sizeof n; +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctz (unsigned int n) +{ + return __gl_stdbit_ctzl (n | (1ul << (8 * sizeof n - 1) << 1)); +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzll (unsigned long long int n) +{ +# ifdef _M_X64 + unsigned long int r; + return _BitScanForward64 (&r, n) ? r : 8 * sizeof n; +# else + unsigned int lo = n; + return __gl_stdbit_ctzl (lo ? lo : n >> 32) + (lo ? 0 : 32); +# endif +} + +#else /* !_MSC_VER */ + +_GL_STDBIT_INLINE int +__gl_stdbit_ctz (unsigned int n) +{ + return 8 * sizeof n - (n ? __gl_stdbit_clz (n & -n) + 1 : 0); +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzl (unsigned long int n) +{ + return 8 * sizeof n - (n ? __gl_stdbit_clzl (n & -n) + 1 : 0); +} +_GL_STDBIT_INLINE int +__gl_stdbit_ctzll (unsigned long long int n) +{ + return 8 * sizeof n - (n ? __gl_stdbit_clzll (n & -n) + 1 : 0); +} +#endif + +#if @GL_STDC_COUNT_ONES@ +/* Count 1 bits in N. */ +# ifdef _GL_STDBIT_HAS_BUILTIN_POPCOUNT +# define __gl_stdbit_popcount __builtin_popcount +# define __gl_stdbit_popcountl __builtin_popcountl +# define __gl_stdbit_popcountll __builtin_popcountll +# else +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcount_wide (unsigned long long int n) +{ + if (sizeof n & (sizeof n - 1)) + { + /* Use a simple O(log N) loop on theoretical platforms where N's + width is not a power of 2. */ + int count = 0; + for (int i = 0; i < 8 * sizeof n; i++, n >>= 1) + count += n & 1; + return count; + } + else + { + /* N's width is a power of 2; count in parallel. */ + unsigned long long int + max = -1ull, + x555555 = max / (1 << 1 | 1), /* 0x555555... */ + x333333 = max / (1 << 2 | 1), /* 0x333333... */ + x0f0f0f = max / (1 << 4 | 1), /* 0x0f0f0f... */ + x010101 = max / ((1 << 8) - 1), /* 0x010101... */ + x000_7f = max / 0xffffffffffffffff * 0x7f; /* 0x000000000000007f... */ + n -= (n >> 1) & x555555; + n = (n & x333333) + ((n >> 2) & x333333); + n = (n + (n >> 4)) & x0f0f0f; + + /* If the popcount always fits in 8 bits, multiply so that the + popcount is in the leading 8 bits of the product; these days + this is typically faster than the alternative below. */ + if (8 * sizeof n < 1 << 8) + return n * x010101 >> 8 * (sizeof n - 1); + + /* N is at least 256 bits wide! Fall back on an O(log log N) + loop that a compiler could unroll. Unroll the first three + iterations by hand, to skip some division and masking. This + is the most we can easily do without hassling with constants + that a typical-platform compiler would reject. */ + n += n >> (1 << 3); + n += n >> (1 << 4); + n += n >> (1 << 5); + n &= x000_7f; + for (int i = 64; i < 8 * sizeof n; i <<= 1) + n = (n + (n >> i)) & max / (1ull << i | 1); + return n; + } +} + +# ifdef _MSC_VER +# if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) +/* Declare the few MSVC intrinsics that we need. We prefer not to include + because it would pollute the namespace. */ +extern void __cpuid (int[4], int); +# pragma intrinsic (__cpuid) +extern unsigned int __popcnt (unsigned int); +# pragma intrinsic (__popcnt) +# ifdef _M_X64 +extern unsigned long long __popcnt64 (unsigned long long); +# pragma intrinsic (__popcnt64) +# else +_GL_STDC_COUNT_ONES_INLINE int +__popcnt64 (unsigned long long int n) +{ + return __popcnt (n >> 32) + __popcnt (n); +} +# endif +# endif + +/* 1 if supported, -1 if not, 0 if unknown. */ +extern signed char __gl_stdbit_popcount_support; + +_GL_STDC_COUNT_ONES_INLINE bool +__gl_stdbit_popcount_supported (void) +{ + if (!__gl_stdbit_popcount_support) + { + /* Do as described in + + Although Microsoft started requiring POPCNT in MS-Windows 11 24H2, + we'll be more cautious. */ + int cpu_info[4]; + __cpuid (cpu_info, 1); + __gl_stdbit_popcount_support = cpu_info[2] & 1 << 23 ? 1 : -1; + } + return 0 < __gl_stdbit_popcount_support; +} +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcount (unsigned int n) +{ + return (__gl_stdbit_popcount_supported () + ? __popcnt (n) + : __gl_stdbit_popcount_wide (n)); +} +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcountl (unsigned long int n) +{ + return (__gl_stdbit_popcount_supported () + ? __popcnt (n) + : __gl_stdbit_popcount_wide (n)); +} +_GL_STDC_COUNT_ONES_INLINE int +__gl_stdbit_popcountll (unsigned long long int n) +{ + return (__gl_stdbit_popcount_supported () + ? __popcnt64 (n) + : __gl_stdbit_popcount_wide (n)); +} +# else /* !_MSC_VER */ +# define __gl_stdbit_popcount __gl_stdbit_popcount_wide +# define __gl_stdbit_popcountl __gl_stdbit_popcount_wide +# define __gl_stdbit_popcountll __gl_stdbit_popcount_wide +# endif +# endif +#endif + + +/* ISO C 23 § 7.18.3 Count Leading Zeros */ + +#if @GL_STDC_LEADING_ZEROS@ + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ui (unsigned int n) +{ + return __gl_stdbit_clz (n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_uc (unsigned char n) +{ + return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_us (unsigned short int n) +{ + return stdc_leading_zeros_ui (n) - 8 * (sizeof 0u - sizeof n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ul (unsigned long int n) +{ + return __gl_stdbit_clzl (n); +} + +_GL_STDC_LEADING_ZEROS_INLINE unsigned int +stdc_leading_zeros_ull (unsigned long long int n) +{ + return __gl_stdbit_clzll (n); +} + +# define stdc_leading_zeros(n) \ + (sizeof (n) == 1 ? stdc_leading_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_leading_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_leading_zeros_ul (n) \ + : stdc_leading_zeros_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.4 Count Leading Ones */ + +#if @GL_STDC_LEADING_ONES@ + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_uc (unsigned char n) +{ + return stdc_leading_zeros_uc (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_us (unsigned short int n) +{ + return stdc_leading_zeros_us (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ui (unsigned int n) +{ + return stdc_leading_zeros_ui (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ul (unsigned long int n) +{ + return stdc_leading_zeros_ul (~n); +} + +_GL_STDC_LEADING_ONES_INLINE unsigned int +stdc_leading_ones_ull (unsigned long long int n) +{ + return stdc_leading_zeros_ull (~n); +} + +# define stdc_leading_ones(n) \ + (sizeof (n) == 1 ? stdc_leading_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_leading_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_leading_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_leading_ones_ul (n) \ + : stdc_leading_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.5 Count Trailing Zeros */ + +#if @GL_STDC_TRAILING_ZEROS@ + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ui (unsigned int n) +{ + return __gl_stdbit_ctz (n); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_uc (unsigned char n) +{ + return stdc_trailing_zeros_ui (n | (1 + (unsigned char) -1)); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_us (unsigned short int n) +{ + return stdc_trailing_zeros_ui (n | (1 + (unsigned short int) -1)); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ul (unsigned long int n) +{ + return __gl_stdbit_ctzl (n); +} + +_GL_STDC_TRAILING_ZEROS_INLINE unsigned int +stdc_trailing_zeros_ull (unsigned long long int n) +{ + return __gl_stdbit_ctzll (n); +} + +# define stdc_trailing_zeros(n) \ + (sizeof (n) == 1 ? stdc_trailing_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_trailing_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_trailing_zeros_ul (n) \ + : stdc_trailing_zeros_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.6 Count Trailing Ones */ + +#if @GL_STDC_TRAILING_ONES@ + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_uc (unsigned char n) +{ + return stdc_trailing_zeros_uc (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_us (unsigned short int n) +{ + return stdc_trailing_zeros_us (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ui (unsigned int n) +{ + return stdc_trailing_zeros_ui (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ul (unsigned long int n) +{ + return stdc_trailing_zeros_ul (~n); +} + +_GL_STDC_TRAILING_ONES_INLINE unsigned int +stdc_trailing_ones_ull (unsigned long long int n) +{ + return stdc_trailing_zeros_ull (~n); +} + +# define stdc_trailing_ones(n) \ + (sizeof (n) == 1 ? stdc_trailing_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_trailing_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_trailing_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_trailing_ones_ul (n) \ + : stdc_trailing_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.7 First Leading Zero */ + +#if @GL_STDC_FIRST_LEADING_ZERO@ + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_uc (unsigned char n) +{ + unsigned int count = stdc_leading_ones_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_us (unsigned short int n) +{ + unsigned int count = stdc_leading_ones_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ui (unsigned int n) +{ + unsigned int count = stdc_leading_ones_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ul (unsigned long int n) +{ + unsigned int count = stdc_leading_ones_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ZERO_INLINE unsigned int +stdc_first_leading_zero_ull (unsigned long long int n) +{ + unsigned int count = stdc_leading_ones_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define stdc_first_leading_zero(n) \ + (sizeof (n) == 1 ? stdc_first_leading_zero_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_zero_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_leading_zero_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_leading_zero_ul (n) \ + : stdc_first_leading_zero_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.8 First Leading One */ + +#if @GL_STDC_FIRST_LEADING_ONE@ + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_uc (unsigned char n) +{ + unsigned int count = stdc_leading_zeros_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_us (unsigned short int n) +{ + unsigned int count = stdc_leading_zeros_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ui (unsigned int n) +{ + unsigned int count = stdc_leading_zeros_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ul (unsigned long int n) +{ + unsigned int count = stdc_leading_zeros_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_LEADING_ONE_INLINE unsigned int +stdc_first_leading_one_ull (unsigned long long int n) +{ + unsigned int count = stdc_leading_zeros_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define stdc_first_leading_one(n) \ + (sizeof (n) == 1 ? stdc_first_leading_one_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_leading_one_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_leading_one_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_leading_one_ul (n) \ + : stdc_first_leading_one_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.9 First Trailing Zero */ + +#if @GL_STDC_FIRST_TRAILING_ZERO@ + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_uc (unsigned char n) +{ + unsigned int count = stdc_trailing_ones_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_us (unsigned short int n) +{ + unsigned int count = stdc_trailing_ones_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ui (unsigned int n) +{ + unsigned int count = stdc_trailing_ones_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ul (unsigned long int n) +{ + unsigned int count = stdc_trailing_ones_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ZERO_INLINE unsigned int +stdc_first_trailing_zero_ull (unsigned long long int n) +{ + unsigned int count = stdc_trailing_ones_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +# define stdc_first_trailing_zero(n) \ + (sizeof (n) == 1 ? stdc_first_trailing_zero_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_zero_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_trailing_zero_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_trailing_zero_ul (n) \ + : stdc_first_trailing_zero_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.10 First Trailing One */ + +#if @GL_STDC_FIRST_TRAILING_ONE@ + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_uc (unsigned char n) +{ + unsigned int count = stdc_trailing_zeros_uc (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_us (unsigned short int n) +{ + unsigned int count = stdc_trailing_zeros_us (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ui (unsigned int n) +{ + unsigned int count = stdc_trailing_zeros_ui (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ul (unsigned long int n) +{ + unsigned int count = stdc_trailing_zeros_ul (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +_GL_STDC_FIRST_TRAILING_ONE_INLINE unsigned int +stdc_first_trailing_one_ull (unsigned long long int n) +{ + unsigned int count = stdc_trailing_zeros_ull (n); + unsigned int bits = 8 * sizeof n; + return count % bits + (count < bits); +} + +#define stdc_first_trailing_one(n) \ + (sizeof (n) == 1 ? stdc_first_trailing_one_uc (n) \ + : sizeof (n) == sizeof (unsigned short) ? stdc_first_trailing_one_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_first_trailing_one_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_first_trailing_one_ul (n) \ + : stdc_first_trailing_one_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.12 Count Ones */ + +#if @GL_STDC_COUNT_ONES@ + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_ui (unsigned int n) +{ + return __gl_stdbit_popcount (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_uc (unsigned char n) +{ + return stdc_count_ones_ui (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_us (unsigned short int n) +{ + return stdc_count_ones_ui (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_ul (unsigned long int n) +{ + return __gl_stdbit_popcountl (n); +} + +_GL_STDC_COUNT_ONES_INLINE unsigned int +stdc_count_ones_ull (unsigned long long int n) +{ + return __gl_stdbit_popcountll (n); +} + +# define stdc_count_ones(n) \ + (sizeof (n) == 1 ? stdc_count_ones_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_count_ones_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_count_ones_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_count_ones_ul (n) \ + : stdc_count_ones_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.11 Count Zeros */ + +#if @GL_STDC_COUNT_ZEROS@ + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_uc (unsigned char n) +{ + return stdc_count_ones_uc (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_us (unsigned short int n) +{ + return stdc_count_ones_us (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_ui (unsigned int n) +{ + return stdc_count_ones_ui (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_ul (unsigned long int n) +{ + return stdc_count_ones_ul (~n); +} + +_GL_STDC_COUNT_ZEROS_INLINE unsigned int +stdc_count_zeros_ull (unsigned long long int n) +{ + return stdc_count_ones_ull (~n); +} + +# define stdc_count_zeros(n) \ + (sizeof (n) == 1 ? stdc_count_zeros_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_count_zeros_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_count_zeros_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_count_zeros_ul (n) \ + : stdc_count_zeros_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.13 Single-bit Check */ + +#if @GL_STDC_HAS_SINGLE_BIT@ + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_uc (unsigned char n) +{ + unsigned char n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_us (unsigned short int n) +{ + unsigned short int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_ui (unsigned int n) +{ + unsigned int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_ul (unsigned long int n) +{ + unsigned long int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +_GL_STDC_HAS_SINGLE_BIT_INLINE bool +stdc_has_single_bit_ull (unsigned long long int n) +{ + unsigned long long int n_1 = n - 1, nx = n_1 ^ n; + return n_1 < nx; +} + +# define stdc_has_single_bit(n) \ + ((bool) \ + (sizeof (n) == 1 ? stdc_has_single_bit_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_has_single_bit_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_has_single_bit_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_has_single_bit_ul (n) \ + : stdc_has_single_bit_ull (n))) + +#endif + + +/* ISO C 23 § 7.18.14 Bit Width */ + +#if @GL_STDC_BIT_WIDTH@ + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_uc (unsigned char n) +{ + return 8 * sizeof n - stdc_leading_zeros_uc (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_us (unsigned short int n) +{ + return 8 * sizeof n - stdc_leading_zeros_us (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_ui (unsigned int n) +{ + return 8 * sizeof n - stdc_leading_zeros_ui (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_ul (unsigned long int n) +{ + return 8 * sizeof n - stdc_leading_zeros_ul (n); +} + +_GL_STDC_BIT_WIDTH_INLINE unsigned int +stdc_bit_width_ull (unsigned long long int n) +{ + return 8 * sizeof n - stdc_leading_zeros_ull (n); +} + +# define stdc_bit_width(n) \ + (sizeof (n) == 1 ? stdc_bit_width_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_width_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_width_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_width_ul (n) \ + : stdc_bit_width_ull (n)) + +#endif + + +/* ISO C 23 § 7.18.15 Bit Floor */ + +#if @GL_STDC_BIT_FLOOR@ + +_GL_STDC_BIT_FLOOR_INLINE unsigned char +stdc_bit_floor_uc (unsigned char n) +{ + return n ? 1u << (stdc_bit_width_uc (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned short int +stdc_bit_floor_us (unsigned short int n) +{ + return n ? 1u << (stdc_bit_width_us (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned int +stdc_bit_floor_ui (unsigned int n) +{ + return n ? 1u << (stdc_bit_width_ui (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned long int +stdc_bit_floor_ul (unsigned long int n) +{ + return n ? 1ul << (stdc_bit_width_ul (n) - 1) : 0; +} + +_GL_STDC_BIT_FLOOR_INLINE unsigned long long int +stdc_bit_floor_ull (unsigned long long int n) +{ + return n ? 1ull << (stdc_bit_width_ull (n) - 1) : 0; +} + +# define stdc_bit_floor(n) \ + (_GL_STDBIT_TYPEOF_CAST \ + (n, \ + (sizeof (n) == 1 ? stdc_bit_floor_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_floor_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_floor_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_floor_ul (n) \ + : stdc_bit_floor_ull (n)))) + +#endif + + +/* ISO C 23 § 7.18.16 Bit Ceiling */ + +#if @GL_STDC_BIT_CEIL@ + +_GL_STDC_BIT_CEIL_INLINE unsigned char +stdc_bit_ceil_uc (unsigned char n) +{ + return n <= 1 ? 1 : 2u << (stdc_bit_width_uc (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned short int +stdc_bit_ceil_us (unsigned short int n) +{ + return n <= 1 ? 1 : 2u << (stdc_bit_width_us (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned int +stdc_bit_ceil_ui (unsigned int n) +{ + return n <= 1 ? 1 : 2u << (stdc_bit_width_ui (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned long int +stdc_bit_ceil_ul (unsigned long int n) +{ + return n <= 1 ? 1 : 2ul << (stdc_bit_width_ul (n - 1) - 1); +} + +_GL_STDC_BIT_CEIL_INLINE unsigned long long int +stdc_bit_ceil_ull (unsigned long long int n) +{ + return n <= 1 ? 1 : 2ull << (stdc_bit_width_ull (n - 1) - 1); +} + +# define stdc_bit_ceil(n) \ + (_GL_STDBIT_TYPEOF_CAST \ + (n, \ + (sizeof (n) == 1 ? stdc_bit_ceil_uc (n) \ + : sizeof (n) == sizeof (unsigned short int) ? stdc_bit_ceil_us (n) \ + : sizeof (n) == sizeof 0u ? stdc_bit_ceil_ui (n) \ + : sizeof (n) == sizeof 0ul ? stdc_bit_ceil_ul (n) \ + : stdc_bit_ceil_ull (n)))) + +#endif + + +#ifdef __cplusplus +} +#endif + +_GL_INLINE_HEADER_END + +#endif /* STDBIT_H */ diff --git a/lib/count-trailing-zeros.c b/lib/stdc_bit_width.c similarity index 78% rename from lib/count-trailing-zeros.c rename to lib/stdc_bit_width.c index e13f77788da..a0dc8de3b5f 100644 --- a/lib/count-trailing-zeros.c +++ b/lib/stdc_bit_width.c @@ -1,6 +1,5 @@ -/* Count the number of trailing 0 bits in a word. - - Copyright 2013-2024 Free Software Foundation, Inc. +/* stdc_bit_width_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,5 +16,5 @@ #include -#define COUNT_TRAILING_ZEROS_INLINE _GL_EXTERN_INLINE -#include "count-trailing-zeros.h" +#define _GL_STDC_BIT_WIDTH_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/count-one-bits.c b/lib/stdc_count_ones.c similarity index 78% rename from lib/count-one-bits.c rename to lib/stdc_count_ones.c index 54b87088028..7421178adf0 100644 --- a/lib/count-one-bits.c +++ b/lib/stdc_count_ones.c @@ -1,6 +1,5 @@ -/* Count the number of 1-bits in a word. - - Copyright (C) 2012-2024 Free Software Foundation, Inc. +/* stdc_count_ones_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,9 +16,9 @@ #include -#define COUNT_ONE_BITS_INLINE _GL_EXTERN_INLINE -#include "count-one-bits.h" +#define _GL_STDC_COUNT_ONES_INLINE _GL_EXTERN_INLINE +#include #if 1500 <= _MSC_VER && (defined _M_IX86 || defined _M_X64) -int popcount_support = -1; +signed char __gl_stdbit_popcount_support; #endif diff --git a/lib/count-leading-zeros.c b/lib/stdc_leading_zeros.c similarity index 77% rename from lib/count-leading-zeros.c rename to lib/stdc_leading_zeros.c index 2bbfd674849..45695e51aa8 100644 --- a/lib/count-leading-zeros.c +++ b/lib/stdc_leading_zeros.c @@ -1,6 +1,5 @@ -/* Count the number of leading 0 bits in a word. - - Copyright (C) 2012-2024 Free Software Foundation, Inc. +/* stdc_leading_zeros_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. This file is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as @@ -17,5 +16,5 @@ #include -#define COUNT_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE -#include "count-leading-zeros.h" +#define _GL_STDC_LEADING_ZEROS_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/stdc_trailing_zeros.c b/lib/stdc_trailing_zeros.c new file mode 100644 index 00000000000..f4bc43ac6ba --- /dev/null +++ b/lib/stdc_trailing_zeros.c @@ -0,0 +1,20 @@ +/* stdc_trailing_zeros_* functions. + Copyright (C) 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +#define _GL_STDC_TRAILING_ZEROS_INLINE _GL_EXTERN_INLINE +#include diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 61040987b57..4dd1e68d15c 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -63,9 +63,6 @@ AC_DEFUN([gl_EARLY], # Code from module cloexec: # Code from module close-stream: # Code from module copy-file-range: - # Code from module count-leading-zeros: - # Code from module count-one-bits: - # Code from module count-trailing-zeros: # Code from module crypto/md5: # Code from module crypto/md5-buffer: # Code from module crypto/sha1-buffer: @@ -174,7 +171,12 @@ AC_DEFUN([gl_EARLY], # Code from module ssize_t: # Code from module stat-time: # Code from module std-gnu11: + # Code from module stdbit-h: # Code from module stdbool: + # Code from module stdc_bit_width: + # Code from module stdc_count_ones: + # Code from module stdc_leading_zeros: + # Code from module stdc_trailing_zeros: # Code from module stdckdint: # Code from module stddef: # Code from module stdint: @@ -514,7 +516,18 @@ AC_DEFUN([gl_INIT], gt_TYPE_SSIZE_T gl_STAT_TIME gl_STAT_BIRTHTIME + gl_STDBIT_H + gl_CONDITIONAL_HEADER([stdbit.h]) + AC_PROG_MKDIR_P gl_C_BOOL + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_BIT_WIDTH=1 + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_COUNT_ONES=1 + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_LEADING_ZEROS=1 + AC_REQUIRE([gl_STDBIT_H]) + GL_STDC_TRAILING_ZEROS=1 AC_CHECK_HEADERS_ONCE([stdckdint.h]) if test $ac_cv_header_stdckdint_h = yes; then GL_GENERATE_STDCKDINT_H=false @@ -673,6 +686,7 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c=false gl_gnulib_enabled_strtoll=false gl_gnulib_enabled_utimens=false + gl_gnulib_enabled_verify=false gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec=false func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b () { @@ -953,6 +967,12 @@ AC_DEFUN([gl_INIT], gl_gnulib_enabled_utimens=true fi } + func_gl_gnulib_m4code_verify () + { + if $gl_gnulib_enabled_verify; then :; else + gl_gnulib_enabled_verify=true + fi + } func_gl_gnulib_m4code_682e609604ccaac6be382e4ee3a4eaec () { if $gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec; then :; else @@ -1016,6 +1036,9 @@ AC_DEFUN([gl_INIT], if case $host_os in mingw* | windows*) false;; *) test $HAVE_GETRANDOM = 0 || test $REPLACE_GETRANDOM = 1;; esac; then func_gl_gnulib_m4code_open fi + if test $REPLACE_MKTIME = 1; then + func_gl_gnulib_m4code_verify + fi if test $HAVE_READLINKAT = 0 || test $REPLACE_READLINKAT = 1; then func_gl_gnulib_m4code_260941c0e5dc67ec9e87d1fb321c300b fi @@ -1025,6 +1048,9 @@ AC_DEFUN([gl_INIT], if test $ac_use_included_regex = yes; then func_gl_gnulib_m4code_fd38c7e463b54744b77b98aeafb4fa7c fi + if test $ac_use_included_regex = yes; then + func_gl_gnulib_m4code_verify + fi if test $HAVE_DECL_STRTOIMAX = 0 || test $REPLACE_STRTOIMAX = 1; then func_gl_gnulib_m4code_strtoll fi @@ -1065,6 +1091,7 @@ AC_DEFUN([gl_INIT], AM_CONDITIONAL([gl_GNULIB_ENABLED_6099e9737f757db36c47fa9d9f02e88c], [$gl_gnulib_enabled_6099e9737f757db36c47fa9d9f02e88c]) AM_CONDITIONAL([gl_GNULIB_ENABLED_strtoll], [$gl_gnulib_enabled_strtoll]) AM_CONDITIONAL([gl_GNULIB_ENABLED_utimens], [$gl_gnulib_enabled_utimens]) + AM_CONDITIONAL([gl_GNULIB_ENABLED_verify], [$gl_gnulib_enabled_verify]) AM_CONDITIONAL([gl_GNULIB_ENABLED_682e609604ccaac6be382e4ee3a4eaec], [$gl_gnulib_enabled_682e609604ccaac6be382e4ee3a4eaec]) # End of code from modules m4_ifval(gl_LIBSOURCES_LIST, [ @@ -1276,12 +1303,6 @@ AC_DEFUN([gl_FILE_LIST], [ lib/close-stream.c lib/close-stream.h lib/copy-file-range.c - lib/count-leading-zeros.c - lib/count-leading-zeros.h - lib/count-one-bits.c - lib/count-one-bits.h - lib/count-trailing-zeros.c - lib/count-trailing-zeros.h lib/diffseq.h lib/dirent-private.h lib/dirent.in.h @@ -1414,6 +1435,12 @@ AC_DEFUN([gl_FILE_LIST], [ lib/signal.in.h lib/stat-time.c lib/stat-time.h + lib/stdbit.c + lib/stdbit.in.h + lib/stdc_bit_width.c + lib/stdc_count_ones.c + lib/stdc_leading_zeros.c + lib/stdc_trailing_zeros.c lib/stdckdint.in.h lib/stddef.in.h lib/stdint.in.h @@ -1567,6 +1594,7 @@ AC_DEFUN([gl_FILE_LIST], [ m4/stat-time.m4 m4/std-gnu11.m4 m4/stdalign.m4 + m4/stdbit_h.m4 m4/stddef_h.m4 m4/stdint.m4 m4/stdio_h.m4 diff --git a/m4/stdbit_h.m4 b/m4/stdbit_h.m4 new file mode 100644 index 00000000000..6af813f39dc --- /dev/null +++ b/m4/stdbit_h.m4 @@ -0,0 +1,37 @@ +# stdbit_h.m4 +# serial 2 +dnl Copyright 2024 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl A placeholder for , for platforms that have issues. + +AC_DEFUN_ONCE([gl_STDBIT_H], +[ + AC_REQUIRE([gl_BIGENDIAN]) + + AC_CHECK_HEADERS_ONCE([stdbit.h]) + if test $ac_cv_header_stdbit_h = yes; then + GL_GENERATE_STDBIT_H=false + else + GL_GENERATE_STDBIT_H=true + fi + + dnl We don't use gl_MODULE_INDICATOR_INIT_VARIABLE here, because stdbit.in.h + dnl does not use #include_next. + GL_STDC_LEADING_ZEROS=0; AC_SUBST([GL_STDC_LEADING_ZEROS]) + GL_STDC_LEADING_ONES=0; AC_SUBST([GL_STDC_LEADING_ONES]) + GL_STDC_TRAILING_ZEROS=0; AC_SUBST([GL_STDC_TRAILING_ZEROS]) + GL_STDC_TRAILING_ONES=0; AC_SUBST([GL_STDC_TRAILING_ONES]) + GL_STDC_FIRST_LEADING_ZERO=0; AC_SUBST([GL_STDC_FIRST_LEADING_ZERO]) + GL_STDC_FIRST_LEADING_ONE=0; AC_SUBST([GL_STDC_FIRST_LEADING_ONE]) + GL_STDC_FIRST_TRAILING_ZERO=0; AC_SUBST([GL_STDC_FIRST_TRAILING_ZERO]) + GL_STDC_FIRST_TRAILING_ONE=0; AC_SUBST([GL_STDC_FIRST_TRAILING_ONE]) + GL_STDC_COUNT_ZEROS=0; AC_SUBST([GL_STDC_COUNT_ZEROS]) + GL_STDC_COUNT_ONES=0; AC_SUBST([GL_STDC_COUNT_ONES]) + GL_STDC_HAS_SINGLE_BIT=0; AC_SUBST([GL_STDC_HAS_SINGLE_BIT]) + GL_STDC_BIT_WIDTH=0; AC_SUBST([GL_STDC_BIT_WIDTH]) + GL_STDC_BIT_FLOOR=0; AC_SUBST([GL_STDC_BIT_FLOOR]) + GL_STDC_BIT_CEIL=0; AC_SUBST([GL_STDC_BIT_CEIL]) +]) diff --git a/src/data.c b/src/data.c index ea611ad1abf..30d8eab7359 100644 --- a/src/data.c +++ b/src/data.c @@ -23,8 +23,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include -#include #include #include "lisp.h" @@ -3500,12 +3498,8 @@ representation. */) } eassume (FIXNUMP (value)); - EMACS_INT v = XFIXNUM (value) < 0 ? -1 - XFIXNUM (value) : XFIXNUM (value); - return make_fixnum (EMACS_UINT_WIDTH <= UINT_WIDTH - ? count_one_bits (v) - : EMACS_UINT_WIDTH <= ULONG_WIDTH - ? count_one_bits_l (v) - : count_one_bits_ll (v)); + EMACS_UINT v = XFIXNUM (value) < 0 ? -1 - XFIXNUM (value) : XFIXNUM (value); + return make_fixnum (stdc_count_ones (v)); } DEFUN ("ash", Fash, Sash, 2, 2, 0, @@ -3662,36 +3656,6 @@ bool_vector_spare_mask (EMACS_INT nr_bits) return (((bits_word) 1) << (nr_bits % BITS_PER_BITS_WORD)) - 1; } -/* Shift VAL right by the width of an unsigned long long. - ULLONG_WIDTH must be less than BITS_PER_BITS_WORD. */ - -static bits_word -shift_right_ull (bits_word w) -{ - /* Pacify bogus GCC warning about shift count exceeding type width. */ - int shift = ULLONG_WIDTH - BITS_PER_BITS_WORD < 0 ? ULLONG_WIDTH : 0; - return w >> shift; -} - -/* Return the number of 1 bits in W. */ - -static int -count_one_bits_word (bits_word w) -{ - if (BITS_WORD_MAX <= UINT_MAX) - return count_one_bits (w); - else if (BITS_WORD_MAX <= ULONG_MAX) - return count_one_bits_l (w); - else - { - int i = 0, count = 0; - while (count += count_one_bits_ll (w), - (i += ULLONG_WIDTH) < BITS_PER_BITS_WORD) - w = shift_right_ull (w); - return count; - } -} - enum bool_vector_op { bool_vector_exclusive_or, bool_vector_union, bool_vector_intersection, @@ -3798,55 +3762,6 @@ bool_vector_binop_driver (Lisp_Object a, return dest; } -/* PRECONDITION must be true. Return VALUE. This odd construction - works around a bogus GCC diagnostic "shift count >= width of type". */ - -static int -pre_value (bool precondition, int value) -{ - eassume (precondition); - return precondition ? value : 0; -} - -/* Compute the number of trailing zero bits in val. If val is zero, - return the number of bits in val. */ -static int -count_trailing_zero_bits (bits_word val) -{ - if (BITS_WORD_MAX == UINT_MAX) - return count_trailing_zeros (val); - if (BITS_WORD_MAX == ULONG_MAX) - return count_trailing_zeros_l (val); - if (BITS_WORD_MAX == ULLONG_MAX) - return count_trailing_zeros_ll (val); - - /* The rest of this code is for the unlikely platform where bits_word differs - in width from unsigned int, unsigned long, and unsigned long long. */ - val |= ~ BITS_WORD_MAX; - if (BITS_WORD_MAX <= UINT_MAX) - return count_trailing_zeros (val); - if (BITS_WORD_MAX <= ULONG_MAX) - return count_trailing_zeros_l (val); - else - { - int count; - for (count = 0; - count < BITS_PER_BITS_WORD - ULLONG_WIDTH; - count += ULLONG_WIDTH) - { - if (val & ULLONG_MAX) - return count + count_trailing_zeros_ll (val); - val = shift_right_ull (val); - } - - if (BITS_PER_BITS_WORD % ULLONG_WIDTH != 0 - && BITS_WORD_MAX == (bits_word) -1) - val |= (bits_word) 1 << pre_value (ULONG_MAX < BITS_WORD_MAX, - BITS_PER_BITS_WORD % ULLONG_WIDTH); - return count + count_trailing_zeros_ll (val); - } -} - DEFUN ("bool-vector-exclusive-or", Fbool_vector_exclusive_or, Sbool_vector_exclusive_or, 2, 3, 0, doc: /* Return A ^ B, bitwise exclusive or. @@ -3961,7 +3876,7 @@ value from A's length. */) adata = bool_vector_data (a); for (i = 0; i < nwords; i++) - count += count_one_bits_word (adata[i]); + count += stdc_count_ones (adata[i]); return make_fixnum (count); } @@ -4009,7 +3924,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) /* Do not count the pad bits. */ mword |= (bits_word) 1 << (BITS_PER_BITS_WORD - offset); - count = count_trailing_zero_bits (mword); + count = stdc_trailing_zeros (mword); pos++; if (count + offset < BITS_PER_BITS_WORD) return make_fixnum (count); @@ -4029,7 +3944,7 @@ A is a bool vector, B is t or nil, and I is an index into A. */) in the current mword. */ mword = bits_word_to_host_endian (adata[pos]); mword ^= twiddle; - count += count_trailing_zero_bits (mword); + count += stdc_trailing_zeros (mword); } else if (nr_bits % BITS_PER_BITS_WORD != 0) { diff --git a/src/lisp.h b/src/lisp.h index 8ee37f5298a..d61a4d5c982 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -23,6 +23,7 @@ along with GNU Emacs. If not, see . */ #include #include #include +#include #include #include #include @@ -37,7 +38,6 @@ along with GNU Emacs. If not, see . */ #include #include -#include #include #include @@ -4148,11 +4148,12 @@ integer_to_uintmax (Lisp_Object num, uintmax_t *n) } } -/* Return floor (log2 (N)) as an int, where 0 < N <= ULLONG_MAX. */ +/* Return floor (log2 (N)) as an int. If N is zero, return -1. */ INLINE int elogb (unsigned long long int n) { - return ULLONG_WIDTH - 1 - count_leading_zeros_ll (n); + int width = stdc_bit_width (n); + return width - 1; } /* A modification count. These are wide enough, and incremented commit 08550d058f028e0819ba6a72e9a53c0bc789257e Author: Paul Eggert Date: Sat May 18 09:33:03 2024 -0700 Update from Gnulib by running admin/merge-gnulib diff --git a/lib/byteswap.c b/lib/byteswap.c new file mode 100644 index 00000000000..6e3dad74eaa --- /dev/null +++ b/lib/byteswap.c @@ -0,0 +1,21 @@ +/* Inline functions for . + + Copyright 2024 Free Software Foundation, Inc. + + This file is free software: you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + This file is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . */ + +#include + +#define _GL_BYTESWAP_INLINE _GL_EXTERN_INLINE +#include diff --git a/lib/byteswap.in.h b/lib/byteswap.in.h index 8e49efad05a..4be335d9158 100644 --- a/lib/byteswap.in.h +++ b/lib/byteswap.in.h @@ -16,29 +16,100 @@ along with this program. If not, see . */ #ifndef _GL_BYTESWAP_H -#define _GL_BYTESWAP_H +#define _GL_BYTESWAP_H 1 + +/* This file uses _GL_INLINE. */ +#if !_GL_CONFIG_H_INCLUDED + #error "Please include config.h first." +#endif + +#include + +_GL_INLINE_HEADER_BEGIN +#ifndef _GL_BYTESWAP_INLINE +# define _GL_BYTESWAP_INLINE _GL_INLINE +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) +# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 true +#elif defined __has_builtin +# if __has_builtin (__builtin_bswap16) +# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 true +# endif +#endif + +#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) +# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 true +# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 true +#elif defined __has_builtin +# if __has_builtin (__builtin_bswap32) +# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 true +# endif +# if __has_builtin (__builtin_bswap64) +# define _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 true +# endif +#endif /* Given an unsigned 16-bit argument X, return the value corresponding to X with reversed byte order. */ -#define bswap_16(x) ((((x) & 0x00FF) << 8) | \ - (((x) & 0xFF00) >> 8)) +_GL_BYTESWAP_INLINE uint_least16_t +bswap_16 (uint_least16_t x) +{ +#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP16 + return __builtin_bswap16 (x); +#else + uint_fast16_t mask = 0xff; + return ( (x & mask << 8 * 1) >> 8 * 1 + | (x & mask << 8 * 0) << 8 * 1); +#endif +} /* Given an unsigned 32-bit argument X, return the value corresponding to X with reversed byte order. */ -#define bswap_32(x) ((((x) & 0x000000FF) << 24) | \ - (((x) & 0x0000FF00) << 8) | \ - (((x) & 0x00FF0000) >> 8) | \ - (((x) & 0xFF000000) >> 24)) +_GL_BYTESWAP_INLINE uint_least32_t +bswap_32 (uint_least32_t x) +{ +#ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP32 + return __builtin_bswap32 (x); +#else + uint_fast32_t mask = 0xff; + return ( (x & mask << 8 * 3) >> 8 * 3 + | (x & mask << 8 * 2) >> 8 * 1 + | (x & mask << 8 * 1) << 8 * 1 + | (x & mask << 8 * 0) << 8 * 3); +#endif +} +#ifdef UINT_LEAST64_MAX /* Given an unsigned 64-bit argument X, return the value corresponding to X with reversed byte order. */ -#define bswap_64(x) ((((x) & 0x00000000000000FFULL) << 56) | \ - (((x) & 0x000000000000FF00ULL) << 40) | \ - (((x) & 0x0000000000FF0000ULL) << 24) | \ - (((x) & 0x00000000FF000000ULL) << 8) | \ - (((x) & 0x000000FF00000000ULL) >> 8) | \ - (((x) & 0x0000FF0000000000ULL) >> 24) | \ - (((x) & 0x00FF000000000000ULL) >> 40) | \ - (((x) & 0xFF00000000000000ULL) >> 56)) +_GL_BYTESWAP_INLINE uint_least64_t +bswap_64 (uint_least64_t x) +{ +# ifdef _GL_BYTESWAP_HAS_BUILTIN_BSWAP64 + return __builtin_bswap64 (x); +# else + uint_fast64_t mask = 0xff; + return ( (x & mask << 8 * 7) >> 8 * 7 + | (x & mask << 8 * 6) >> 8 * 5 + | (x & mask << 8 * 5) >> 8 * 3 + | (x & mask << 8 * 4) >> 8 * 1 + | (x & mask << 8 * 3) << 8 * 1 + | (x & mask << 8 * 2) << 8 * 3 + | (x & mask << 8 * 1) << 8 * 5 + | (x & mask << 8 * 0) << 8 * 7); +# endif +} +#endif + +#ifdef __cplusplus +} +#endif + +_GL_INLINE_HEADER_END #endif /* _GL_BYTESWAP_H */ diff --git a/lib/count-leading-zeros.h b/lib/count-leading-zeros.h index 545749d6d27..a4b68c21064 100644 --- a/lib/count-leading-zeros.h +++ b/lib/count-leading-zeros.h @@ -45,8 +45,10 @@ extern "C" { # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ return x ? BUILTIN (x) : CHAR_BIT * sizeof x; #elif _MSC_VER +extern unsigned char _BitScanReverse (unsigned long *, unsigned long); # pragma intrinsic (_BitScanReverse) # if defined _M_X64 +extern unsigned char _BitScanReverse64 (unsigned long *, unsigned long long); # pragma intrinsic (_BitScanReverse64) # endif # define COUNT_LEADING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ diff --git a/lib/count-one-bits.h b/lib/count-one-bits.h index 8d67f8718a4..24bf8cc2327 100644 --- a/lib/count-one-bits.h +++ b/lib/count-one-bits.h @@ -85,9 +85,12 @@ count_one_bits_32 (unsigned int x) # include # else /* Don't pollute the namespace with too many MSVC intrinsics. */ +extern void __cpuid (int[4], int); # pragma intrinsic (__cpuid) +extern unsigned int __popcnt (unsigned int); # pragma intrinsic (__popcnt) # if defined _M_X64 +extern unsigned long long __popcnt64 (unsigned long long); # pragma intrinsic (__popcnt64) # endif # endif diff --git a/lib/count-trailing-zeros.h b/lib/count-trailing-zeros.h index ed1e0131147..82de8731ec1 100644 --- a/lib/count-trailing-zeros.h +++ b/lib/count-trailing-zeros.h @@ -45,8 +45,10 @@ extern "C" { # define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ return x ? BUILTIN (x) : CHAR_BIT * sizeof x; #elif _MSC_VER +extern unsigned char _BitScanForward (unsigned long *, unsigned long); # pragma intrinsic (_BitScanForward) # if defined _M_X64 +extern unsigned char _BitScanForward64 (unsigned long *, unsigned long long); # pragma intrinsic (_BitScanForward64) # endif # define COUNT_TRAILING_ZEROS(BUILTIN, MSC_BUILTIN, TYPE) \ diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index a5c009cfb85..d03e193b63c 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -361,6 +361,7 @@ GL_GENERATE_MINI_GMP_H_CONDITION = @GL_GENERATE_MINI_GMP_H_CONDITION@ GL_GENERATE_STDCKDINT_H_CONDITION = @GL_GENERATE_STDCKDINT_H_CONDITION@ GL_GENERATE_STDDEF_H_CONDITION = @GL_GENERATE_STDDEF_H_CONDITION@ GL_GENERATE_STDINT_H_CONDITION = @GL_GENERATE_STDINT_H_CONDITION@ +GL_GNULIB_ABORT_DEBUG = @GL_GNULIB_ABORT_DEBUG@ GL_GNULIB_ACCESS = @GL_GNULIB_ACCESS@ GL_GNULIB_ALIGNED_ALLOC = @GL_GNULIB_ALIGNED_ALLOC@ GL_GNULIB_ALPHASORT = @GL_GNULIB_ALPHASORT@ @@ -1107,6 +1108,7 @@ QCOPY_ACL_LIB = @QCOPY_ACL_LIB@ RALLOC_OBJ = @RALLOC_OBJ@ RANLIB = @RANLIB@ READELF = @READELF@ +REPLACE_ABORT = @REPLACE_ABORT@ REPLACE_ACCESS = @REPLACE_ACCESS@ REPLACE_ALIGNED_ALLOC = @REPLACE_ALIGNED_ALLOC@ REPLACE_CALLOC_FOR_CALLOC_GNU = @REPLACE_CALLOC_FOR_CALLOC_GNU@ @@ -1639,6 +1641,7 @@ ifneq (,$(GL_GENERATE_BYTESWAP_H_CONDITION)) byteswap.h: byteswap.in.h $(top_builddir)/config.status $(gl_V_at)$(SED_HEADER_TO_AT_t) $(srcdir)/byteswap.in.h $(AM_V_at)mv $@-t $@ +libgnu_a_SOURCES += byteswap.c else byteswap.h: $(top_builddir)/config.status rm -f $@ @@ -3322,6 +3325,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ -e 's|@''PRAGMA_COLUMNS''@|@PRAGMA_COLUMNS@|g' \ -e 's|@''NEXT_STDLIB_H''@|$(NEXT_STDLIB_H)|g' \ -e 's/@''GNULIB__EXIT''@/$(GL_GNULIB__EXIT)/g' \ + -e 's/@''GNULIB_ABORT_DEBUG''@/$(GL_GNULIB_ABORT_DEBUG)/g' \ -e 's/@''GNULIB_ALIGNED_ALLOC''@/$(GL_GNULIB_ALIGNED_ALLOC)/g' \ -e 's/@''GNULIB_ATOLL''@/$(GL_GNULIB_ATOLL)/g' \ -e 's/@''GNULIB_CALLOC_GNU''@/$(GL_GNULIB_CALLOC_GNU)/g' \ @@ -3424,6 +3428,7 @@ stdlib.h: stdlib.in.h $(top_builddir)/config.status $(CXXDEFS_H) \ < $@-t1 > $@-t2 $(AM_V_at)sed \ -e 's|@''REPLACE__EXIT''@|$(REPLACE__EXIT)|g' \ + -e 's|@''REPLACE_ABORT''@|$(REPLACE_ABORT)|g' \ -e 's|@''REPLACE_ALIGNED_ALLOC''@|$(REPLACE_ALIGNED_ALLOC)|g' \ -e 's|@''REPLACE_CALLOC_FOR_CALLOC_GNU''@|$(REPLACE_CALLOC_FOR_CALLOC_GNU)|g' \ -e 's|@''REPLACE_CALLOC_FOR_CALLOC_POSIX''@|$(REPLACE_CALLOC_FOR_CALLOC_POSIX)|g' \ diff --git a/lib/stdlib.in.h b/lib/stdlib.in.h index e74e7c18d19..1888d3ee314 100644 --- a/lib/stdlib.in.h +++ b/lib/stdlib.in.h @@ -216,6 +216,23 @@ _GL_WARN_ON_USE (_Exit, "_Exit is unportable - " #endif +#if @GNULIB_ABORT_DEBUG@ +# if @REPLACE_ABORT@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# undef abort +# define abort rpl_abort +# endif +_GL_FUNCDECL_RPL (abort, _Noreturn void, (void)); +_GL_CXXALIAS_RPL (abort, void, (void)); +# else +_GL_CXXALIAS_SYS (abort, void, (void)); +# endif +# if __GLIBC__ >= 2 +_GL_CXXALIASWARN (abort); +# endif +#endif + + #if @GNULIB_FREE_POSIX@ # if @REPLACE_FREE@ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) diff --git a/lib/strftime.c b/lib/strftime.c index 9b205e48023..834f3a79f46 100644 --- a/lib/strftime.c +++ b/lib/strftime.c @@ -143,11 +143,11 @@ extern char *tzname[]; enum pad_style { - ZERO_PAD, /* (default) Pad with 0 unless format says otherwise. */ - ALWAYS_ZERO_PAD, /* '0' Always pad with 0. */ - SIGN_PAD, /* '+' Always output a sign. */ - SPACE_PAD, /* '_' Pad with space. */ - NO_PAD /* '-' Do not pad. */ + ZERO_PAD, /* (default) Pad with 0 unless format says otherwise. */ + ALWAYS_ZERO_PAD, /* '0' Always pad with 0. */ + SIGN_PAD, /* '+' Always output a sign. */ + SPACE_PAD, /* '_' Pad with space. */ + NO_PAD /* '-' Do not pad. */ }; #define TM_YEAR_BASE 1900 diff --git a/lib/sys_select.in.h b/lib/sys_select.in.h index de29c77949a..ddf25d1de4c 100644 --- a/lib/sys_select.in.h +++ b/lib/sys_select.in.h @@ -328,7 +328,9 @@ _GL_CXXALIAS_SYS (select, int, (int, fd_set *restrict, fd_set *restrict, fd_set *restrict, timeval *restrict)); # endif +# if __GLIBC__ >= 2 _GL_CXXALIASWARN (select); +# endif #elif @HAVE_WINSOCK2_H@ # undef select # define select select_used_without_requesting_gnulib_module_select diff --git a/lib/unistd.in.h b/lib/unistd.in.h index fa99d7472f4..7dbed38969b 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -1934,11 +1934,7 @@ _GL_CXXALIASWARN (read); # undef read # define read _read # endif -# ifdef __MINGW32__ -_GL_CXXALIAS_MDA (read, int, (int fd, void *buf, unsigned int count)); -# else -_GL_CXXALIAS_MDA (read, ssize_t, (int fd, void *buf, unsigned int count)); -# endif +_GL_CXXALIAS_MDA_CAST (read, ssize_t, (int fd, void *buf, unsigned int count)); # else _GL_CXXALIAS_SYS (read, ssize_t, (int fd, void *buf, size_t count)); # endif @@ -2402,11 +2398,7 @@ _GL_CXXALIASWARN (write); # undef write # define write _write # endif -# ifdef __MINGW32__ -_GL_CXXALIAS_MDA (write, int, (int fd, const void *buf, unsigned int count)); -# else -_GL_CXXALIAS_MDA (write, ssize_t, (int fd, const void *buf, unsigned int count)); -# endif +_GL_CXXALIAS_MDA_CAST (write, ssize_t, (int fd, const void *buf, unsigned int count)); # else _GL_CXXALIAS_SYS (write, ssize_t, (int fd, const void *buf, size_t count)); # endif diff --git a/m4/byteswap.m4 b/m4/byteswap.m4 index 0c76fe9312d..3f5ef45cfe6 100644 --- a/m4/byteswap.m4 +++ b/m4/byteswap.m4 @@ -1,5 +1,5 @@ # byteswap.m4 -# serial 5 +# serial 6 dnl Copyright (C) 2005, 2007, 2009-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -10,9 +10,28 @@ dnl Written by Oskar Liljeblad. AC_DEFUN([gl_BYTESWAP], [ dnl Prerequisites of lib/byteswap.in.h. - AC_CHECK_HEADERS([byteswap.h], [ + AC_CHECK_HEADERS_ONCE([byteswap.h]) + if test $ac_cv_header_byteswap_h = yes; then + AC_CACHE_CHECK([for working bswap_16, bswap_32, bswap_64], + [gl_cv_header_working_byteswap_h], + [gl_cv_header_working_byteswap_h=no + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + ]], + [[int value_16 = bswap_16 (0.0); + int value_32 = bswap_32 (0.0); + int value_64 = bswap_64 (0.0); + return !(value_16 + value_32 + value_64); + ]]) + ], + [gl_cv_header_working_byteswap_h=yes], + [gl_cv_header_working_byteswap_h=no]) + ]) + fi + if test $gl_cv_header_working_byteswap_h = yes; then GL_GENERATE_BYTESWAP_H=false - ], [ + else GL_GENERATE_BYTESWAP_H=true - ]) + fi ]) diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 index 37f180a8955..61040987b57 100644 --- a/m4/gnulib-comp.m4 +++ b/m4/gnulib-comp.m4 @@ -1259,6 +1259,7 @@ AC_DEFUN([gl_FILE_LIST], [ lib/boot-time-aux.h lib/boot-time.c lib/boot-time.h + lib/byteswap.c lib/byteswap.in.h lib/c++defs.h lib/c-ctype.c diff --git a/m4/stdalign.m4 b/m4/stdalign.m4 index 2b4762f3200..1c29d1e4fb9 100644 --- a/m4/stdalign.m4 +++ b/m4/stdalign.m4 @@ -81,7 +81,7 @@ AC_DEFUN([gl_ALIGNASOF], References: ISO C23 (latest free draft - ) + ) sections 6.5.3.4, 6.7.5, 7.15. C++11 (latest free draft ) diff --git a/m4/stdlib_h.m4 b/m4/stdlib_h.m4 index a4662f29955..bb5a6460414 100644 --- a/m4/stdlib_h.m4 +++ b/m4/stdlib_h.m4 @@ -1,5 +1,5 @@ # stdlib_h.m4 -# serial 77 +# serial 78 dnl Copyright (C) 2007-2024 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -110,6 +110,7 @@ AC_DEFUN([gl_STDLIB_H_REQUIRE_DEFAULTS], [ m4_defun(GL_MODULE_INDICATOR_PREFIX[_STDLIB_H_MODULE_INDICATOR_DEFAULTS], [ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB__EXIT]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ABORT_DEBUG]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ALIGNED_ALLOC]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_ATOLL]) gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_CALLOC_GNU]) @@ -218,6 +219,7 @@ AC_DEFUN([gl_STDLIB_H_DEFAULTS], HAVE_UNLOCKPT=1; AC_SUBST([HAVE_UNLOCKPT]) HAVE_DECL_UNSETENV=1; AC_SUBST([HAVE_DECL_UNSETENV]) REPLACE__EXIT=0; AC_SUBST([REPLACE__EXIT]) + REPLACE_ABORT=0; AC_SUBST([REPLACE_ABORT]) REPLACE_ALIGNED_ALLOC=0; AC_SUBST([REPLACE_ALIGNED_ALLOC]) REPLACE_CALLOC_FOR_CALLOC_GNU=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_GNU]) REPLACE_CALLOC_FOR_CALLOC_POSIX=0; AC_SUBST([REPLACE_CALLOC_FOR_CALLOC_POSIX]) commit c9af2fab9221d3793e0b9cd4dd376f9f16099a26 Author: Stefan Kangas Date: Sat May 18 19:14:21 2024 +0200 List Andrea Corallo as co-maintainer in ack.texi * doc/emacs/ack.texi (Acknowledgments): List Andrea Corallo as co-maintainer from 29.3 onwards. diff --git a/doc/emacs/ack.texi b/doc/emacs/ack.texi index 62f6382113e..c3d86bf3426 100644 --- a/doc/emacs/ack.texi +++ b/doc/emacs/ack.texi @@ -245,7 +245,8 @@ Theresa O'Connor wrote @file{json.el}, a file for parsing and generating JSON files. @item -Andrea Corallo wrote the native compilation support in @file{comp.c} +Andrea Corallo was the Emacs (co-)maintainer from 29.3 onwards. +He wrote the native compilation support in @file{comp.c} and and @file{comp.el}, for compiling Emacs Lisp to native code using @samp{libgccjit}. commit 3b890bf2bd2fec54433f35d61e30542b3dadb612 Author: Eshel Yaron Date: Sat Apr 27 20:47:34 2024 +0200 New functions '(set-)window-cursor-type' * src/window.h (struct window): Add 'cursor_type' slot. (wset_cursor_type): New inline function. * src/xdisp.c (get_window_cursor_type): Consult 'cursor_type'. * src/window.c (make_window): Initialize 'cursor_type' to t. (Fset_window_cursor_type, Fwindow_cursor_type): New functions. (syms_of_window): List their symbols. * doc/lispref/windows.texi (Window Point): Document them. * doc/lispref/frames.texi (Cursor Parameters): Mention new 'set-window-cursor-type'. * etc/NEWS: Announce new functions. (Bug#70622) diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi index cae93acae9f..974def3de10 100644 --- a/doc/lispref/frames.texi +++ b/doc/lispref/frames.texi @@ -2341,9 +2341,9 @@ Display a horizontal bar @var{height} pixels high. @end table @vindex cursor-type -The @code{cursor-type} frame parameter may be overridden by the -variables @code{cursor-type} and -@code{cursor-in-non-selected-windows}: +The @code{cursor-type} frame parameter may be overridden by +@code{set-window-cursor-type} (@pxref{Window Point}), and by the +variables @code{cursor-type} and @code{cursor-in-non-selected-windows}: @defopt cursor-type This buffer-local variable controls how the cursor looks in a selected diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 34f7b260a52..61e72eae680 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -5142,6 +5142,24 @@ Insertion Types}) of @code{window-point}. The default is @code{nil}, so @code{window-point} will stay behind text inserted there. @end defvar +@defun set-window-cursor-type window type +This function sets the cursor shape for @var{window}. This setting +takes precedence over the @code{cursor-type} variable, and @var{type} +has the same format as the value of that variable. @xref{Cursor +Parameters}. If @var{window} is @code{nil}, it means to set the cursor +type for the selected window. + +The initial value for new windows is @code{t}, which says to respect the +buffer-local value of @code{cursor-type}. The value set by this +function persists across buffers shown in @var{window}, so +@code{set-window-buffer} does not reset it. @xref{Buffers and Windows}. +@end defun + +@defun window-cursor-type &optional window +This function returns the cursor type of @var{window}, defaulting to the +selected window. +@end defun + @node Window Start and End @section The Window Start and End Positions @cindex window start position diff --git a/etc/NEWS b/etc/NEWS index 5bf9a2d07c8..e92fc41c4b6 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -340,6 +340,13 @@ and 'window-state-get'. Then later another new variable 'window-state-put' to restore positions of window points according to the context stored in a window parameter. ++++ +*** New functions 'set-window-cursor-type' and 'window-cursor-type'. +'set-window-cursor-type' sets a per-window cursor type, and +'window-cursor-type' queries this setting for a given window. Windows +are always created with a 'window-cursor-type' of t, which means to +consult the variable 'cursor-type' as before. + ** Tab Bars and Tab Lines --- diff --git a/src/window.c b/src/window.c index aac5b087c2c..ff28bac5306 100644 --- a/src/window.c +++ b/src/window.c @@ -4425,6 +4425,7 @@ make_window (void) wset_old_pointm (w, Fmake_marker ()); wset_vertical_scroll_bar_type (w, Qt); wset_horizontal_scroll_bar_type (w, Qt); + wset_cursor_type (w, Qt); /* These Lisp fields are marked specially so they're not set to nil by allocate_window. */ wset_prev_buffers (w, Qnil); @@ -8050,6 +8051,52 @@ PERSISTENT), see `set-window-fringes'. */) w->fringes_persistent ? Qt : Qnil); } +DEFUN ("set-window-cursor-type", Fset_window_cursor_type, + Sset_window_cursor_type, 2, 2, 0, + doc: /* Set the `cursor-type' of WINDOW to TYPE. + +This setting takes precedence over the variable `cursor-type', and TYPE +has the same format as the value of that variable. The initial value +for new windows is t, which says to respect the buffer-local value of +`cursor-type'. + +WINDOW nil means use the selected window. This setting persists across +buffers shown in WINDOW, so `set-window-buffer' does not reset it. */) + (Lisp_Object window, Lisp_Object type) +{ + struct window *w = decode_live_window (window); + + if (!(NILP (type) + || EQ (type, Qt) + || EQ (type, Qbox) + || EQ (type, Qhollow) + || EQ (type, Qbar) + || EQ (type, Qhbar) + || (CONSP (type) + && (EQ (XCAR (type), Qbox) + || EQ (XCAR (type), Qbar) + || EQ (XCAR (type), Qhbar)) + && INTEGERP (XCDR (type))))) + error ("Invalid cursor type"); + + wset_cursor_type (w, type); + + /* Redisplay with updated cursor type. */ + wset_redisplay (w); + + return type; +} + +/* FIXME: Add a way to get the _effective_ cursor type, possibly by + extending this function with an additional optional argument. */ +DEFUN ("window-cursor-type", Fwindow_cursor_type, Swindow_cursor_type, + 0, 1, 0, + doc: /* Return the `cursor-type' of WINDOW. +WINDOW must be a live window and defaults to the selected one. */) + (Lisp_Object window) +{ + return decode_live_window (window)->cursor_type; +} /*********************************************************************** @@ -8985,4 +9032,6 @@ displayed after a scrolling operation to be somewhat inaccurate. */); defsubr (&Swindow_parameters); defsubr (&Swindow_parameter); defsubr (&Sset_window_parameter); + defsubr (&Swindow_cursor_type); + defsubr (&Sset_window_cursor_type); } diff --git a/src/window.h b/src/window.h index 19283725931..86932181252 100644 --- a/src/window.h +++ b/src/window.h @@ -205,6 +205,9 @@ struct window /* An alist with parameters. */ Lisp_Object window_parameters; + /* `cursor-type' to use in this window. */ + Lisp_Object cursor_type; + /* The help echo text for this window. Qnil if there's none. */ Lisp_Object mode_line_help_echo; @@ -542,6 +545,12 @@ wset_horizontal_scroll_bar_type (struct window *w, Lisp_Object val) w->horizontal_scroll_bar_type = val; } +INLINE void +wset_cursor_type (struct window *w, Lisp_Object val) +{ + w->cursor_type = val; +} + INLINE void wset_prev_buffers (struct window *w, Lisp_Object val) { diff --git a/src/xdisp.c b/src/xdisp.c index 63ff8670b79..ba5af7127c6 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -33616,7 +33616,9 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, { if (w == XWINDOW (echo_area_window)) { - if (EQ (BVAR (b, cursor_type), Qt) || NILP (BVAR (b, cursor_type))) + if (!EQ (Qt, w->cursor_type)) + return get_specified_cursor_type (w->cursor_type, width); + else if (EQ (BVAR (b, cursor_type), Qt) || NILP (BVAR (b, cursor_type))) { *width = FRAME_CURSOR_WIDTH (f); return FRAME_DESIRED_CURSOR (f); @@ -33643,18 +33645,23 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, non_selected = true; } - /* Never display a cursor in a window in which cursor-type is nil. */ - if (NILP (BVAR (b, cursor_type))) - return NO_CURSOR; - - /* Get the normal cursor type for this window. */ - if (EQ (BVAR (b, cursor_type), Qt)) + if (!EQ (Qt, w->cursor_type)) + cursor_type = get_specified_cursor_type (w->cursor_type, width); + else { - cursor_type = FRAME_DESIRED_CURSOR (f); - *width = FRAME_CURSOR_WIDTH (f); + /* Never display a cursor in a window in which cursor-type is nil. */ + if (NILP (BVAR (b, cursor_type))) + return NO_CURSOR; + + /* Get the normal cursor type for this window. */ + if (EQ (BVAR (b, cursor_type), Qt)) + { + cursor_type = FRAME_DESIRED_CURSOR (f); + *width = FRAME_CURSOR_WIDTH (f); + } + else + cursor_type = get_specified_cursor_type (BVAR (b, cursor_type), width); } - else - cursor_type = get_specified_cursor_type (BVAR (b, cursor_type), width); /* Use cursor-in-non-selected-windows instead for non-selected window or frame. */ commit 6badb1260a5e5107887d244507a7289fa1a30a91 Author: Dmitry Gutov Date: Sat May 18 16:30:23 2024 +0300 minibuffer-completion-help: Fix earlier mistake * lisp/minibuffer.el (minibuffer-completion-help): Fix earlier mistake. Instead of altering a variable whose value is immutable (and already captured in a saved list), move the reference to said list to a lexical binding and alter that list's second element instead. https://lists.gnu.org/archive/html/emacs-devel/2024-05/msg00875.html diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el index fbd49b569a8..f62cb2566b2 100644 --- a/lisp/minibuffer.el +++ b/lisp/minibuffer.el @@ -2596,6 +2596,7 @@ The candidate will still be chosen by `choose-completion' unless (buffer-substring (point) end)))) (point))) (field-char (and (< field-end end) (char-after field-end))) + (base-position (list (+ start base-size) field-end)) (all-md (completion--metadata (buffer-substring-no-properties start (point)) base-size md @@ -2678,8 +2679,7 @@ The candidate will still be chosen by `choose-completion' unless completions)))) (with-current-buffer standard-output - (setq-local completion-base-position - (list (+ start base-size) field-end)) + (setq-local completion-base-position base-position) (setq-local completion-list-insert-choice-function (lambda (start end choice) (unless (or (zerop (length prefix)) @@ -2702,9 +2702,12 @@ The candidate will still be chosen by `choose-completion' unless (= (aref choice (1- (length choice))) field-char)) (setq end (1+ end))) - (cl-decf field-end (- end start (length choice))) + ;; Tried to use a marker to track buffer changes + ;; but that clashed with another existing marker. + (cl-decf (nth 1 base-position) + (- end start (length choice))) ;; FIXME: Use `md' to do quoting&terminator here. - (completion--replace start end choice) + (completion--replace start (min end (point-max)) choice) (let* ((minibuffer-completion-table ctable) (minibuffer-completion-predicate cpred) (completion-extra-properties cprops) commit 8dc00dc22250b383e7692fc761cbca25b014aa8a Author: Po Lu Date: Sat May 18 20:45:35 2024 +0800 Housekeeping around androidselect.c * java/org/gnu/emacs/EmacsClipboard.java (setClipboard) (getClipboard): * java/org/gnu/emacs/EmacsSdk11Clipboard.java (setClipboard) (getClipboard): * java/org/gnu/emacs/EmacsSdk8Clipboard.java (setClipboard) (getClipboard): Save and return Strings rather than byte arrays. * src/androidselect.c (android_init_emacs_clipboard) (Fandroid_set_clipboard, Fandroid_get_clipboard): Adjust to match. diff --git a/java/org/gnu/emacs/EmacsClipboard.java b/java/org/gnu/emacs/EmacsClipboard.java index 86553f478ed..2560ef793c2 100644 --- a/java/org/gnu/emacs/EmacsClipboard.java +++ b/java/org/gnu/emacs/EmacsClipboard.java @@ -27,10 +27,10 @@ public abstract class EmacsClipboard { - public abstract void setClipboard (byte[] bytes); + public abstract void setClipboard (String string); public abstract int ownsClipboard (); public abstract boolean clipboardExists (); - public abstract byte[] getClipboard (); + public abstract String getClipboard (); public abstract String[] getClipboardTargets (); public abstract AssetFileDescriptor getClipboardData (String target); diff --git a/java/org/gnu/emacs/EmacsSdk11Clipboard.java b/java/org/gnu/emacs/EmacsSdk11Clipboard.java index dfc714476ec..e179551c14d 100644 --- a/java/org/gnu/emacs/EmacsSdk11Clipboard.java +++ b/java/org/gnu/emacs/EmacsSdk11Clipboard.java @@ -86,32 +86,23 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard } } - /* Set the clipboard text to CLIPBOARD, a string in UTF-8 - encoding. */ + /* Save the STRING into the clipboard by way of text copied by the + user. */ @Override public synchronized void - setClipboard (byte[] bytes) + setClipboard (String string) { ClipData data; - String string; - try - { - string = new String (bytes, "UTF-8"); - data = ClipData.newPlainText ("Emacs", string); - manager.setPrimaryClip (data); - ownsClipboard = true; - - /* onPrimaryClipChanged will be called again. Use this - variable to keep track of how many times the clipboard has - been changed. */ - ++clipboardChangedCount; - } - catch (UnsupportedEncodingException exception) - { - Log.w (TAG, "setClipboard: " + exception); - } + data = ClipData.newPlainText ("Emacs", string); + manager.setPrimaryClip (data); + ownsClipboard = true; + + /* onPrimaryClipChanged will be called again. Use this + variable to keep track of how many times the clipboard has + been changed. */ + ++clipboardChangedCount; } /* Return whether or not Emacs owns the clipboard. Value is 1 if @@ -141,7 +132,7 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard NULL if no content is available. */ @Override - public byte[] + public String getClipboard () { ClipData clip; @@ -154,18 +145,8 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard return null; context = EmacsService.SERVICE; - - try - { - text = clip.getItemAt (0).coerceToText (context); - return text.toString ().getBytes ("UTF-8"); - } - catch (UnsupportedEncodingException exception) - { - Log.w (TAG, "getClipboard: " + exception); - } - - return null; + text = clip.getItemAt (0).coerceToText (context); + return text.toString (); } /* Return an array of targets currently provided by the diff --git a/java/org/gnu/emacs/EmacsSdk8Clipboard.java b/java/org/gnu/emacs/EmacsSdk8Clipboard.java index 344ec6f7997..afd235babf5 100644 --- a/java/org/gnu/emacs/EmacsSdk8Clipboard.java +++ b/java/org/gnu/emacs/EmacsSdk8Clipboard.java @@ -52,21 +52,14 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard = (ClipboardManager) context.getSystemService (what); } - /* Set the clipboard text to CLIPBOARD, a string in UTF-8 - encoding. */ + /* Save the STRING into the clipboard by way of text copied by the + user. */ @Override public void - setClipboard (byte[] bytes) + setClipboard (String string) { - try - { - manager.setText (new String (bytes, "UTF-8")); - } - catch (UnsupportedEncodingException exception) - { - Log.w (TAG, "setClipboard: " + exception); - } + manager.setText (string); } /* Return whether or not Emacs owns the clipboard. Value is 1 if @@ -93,7 +86,7 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard NULL if no content is available. */ @Override - public byte[] + public String getClipboard () { String string; @@ -105,17 +98,7 @@ public final class EmacsSdk8Clipboard extends EmacsClipboard return null; string = text.toString (); - - try - { - return string.getBytes ("UTF-8"); - } - catch (UnsupportedEncodingException exception) - { - Log.w (TAG, "getClipboard: " + exception); - } - - return null; + return string; } /* Return an array of targets currently provided by the diff --git a/src/androidselect.c b/src/androidselect.c index 7c93607848a..50982738743 100644 --- a/src/androidselect.c +++ b/src/androidselect.c @@ -94,10 +94,10 @@ android_init_emacs_clipboard (void) name, signature); \ eassert (clipboard_class.c_name); - FIND_METHOD (set_clipboard, "setClipboard", "([B)V"); + FIND_METHOD (set_clipboard, "setClipboard", "(Ljava/lang/String;)V"); FIND_METHOD (owns_clipboard, "ownsClipboard", "()I"); FIND_METHOD (clipboard_exists, "clipboardExists", "()Z"); - FIND_METHOD (get_clipboard, "getClipboard", "()[B"); + FIND_METHOD (get_clipboard, "getClipboard", "()Ljava/lang/String;"); FIND_METHOD (get_clipboard_targets, "getClipboardTargets", "()[Ljava/lang/String;"); FIND_METHOD (get_clipboard_data, "getClipboardData", @@ -151,28 +151,26 @@ DEFUN ("android-set-clipboard", Fandroid_set_clipboard, doc: /* Set the clipboard text to STRING. */) (Lisp_Object string) { - jarray bytes; + jstring text; if (!android_init_gui) error ("Accessing clipboard without display connection"); CHECK_STRING (string); - string = ENCODE_UTF_8 (string); + string = code_convert_string_norecord (string, Qandroid_jni, + true); - bytes = (*android_java_env)->NewByteArray (android_java_env, - SBYTES (string)); + text = (*android_java_env)->NewStringUTF (android_java_env, + SSDATA (string)); android_exception_check (); - (*android_java_env)->SetByteArrayRegion (android_java_env, bytes, - 0, SBYTES (string), - (jbyte *) SDATA (string)); (*android_java_env)->CallVoidMethod (android_java_env, clipboard, clipboard_class.set_clipboard, - bytes); - android_exception_check_1 (bytes); + text); + android_exception_check_1 (text); + ANDROID_DELETE_LOCAL_REF (text); - ANDROID_DELETE_LOCAL_REF (bytes); return Qnil; } @@ -185,39 +183,39 @@ Alternatively, return nil if the clipboard is empty. */) (void) { Lisp_Object string; - jarray bytes; + jstring text; jmethodID method; - size_t length; - jbyte *data; + jsize length; + const char *data; if (!android_init_gui) error ("No Android display connection!"); method = clipboard_class.get_clipboard; - bytes + text = (*android_java_env)->CallObjectMethod (android_java_env, clipboard, method); android_exception_check (); - if (!bytes) + if (!text) return Qnil; - length = (*android_java_env)->GetArrayLength (android_java_env, - bytes); - data = (*android_java_env)->GetByteArrayElements (android_java_env, - bytes, NULL); - android_exception_check_nonnull (data, bytes); - - string = make_unibyte_string ((char *) data, length); + /* Retrieve a pointer to the raw JNI-encoded bytes of the string. */ + length = (*android_java_env)->GetStringUTFLength (android_java_env, + text); + data = (*android_java_env)->GetStringUTFChars (android_java_env, text, + NULL); + android_exception_check_nonnull ((void *) data, text); - (*android_java_env)->ReleaseByteArrayElements (android_java_env, - bytes, data, - JNI_ABORT); - ANDROID_DELETE_LOCAL_REF (bytes); + /* Copy them into a unibyte string for decoding. */ + string = make_unibyte_string (data, length); + (*android_java_env)->ReleaseStringUTFChars (android_java_env, text, + data); + ANDROID_DELETE_LOCAL_REF (text); /* Now decode the resulting string. */ - return code_convert_string_norecord (string, Qutf_8, false); + return code_convert_string_norecord (string, Qandroid_jni, false); } DEFUN ("android-clipboard-exists-p", Fandroid_clipboard_exists_p, commit 5ec4c1a7d3f0d184982f4efa0c01bc9a76197533 Merge: 2e862f81a35 a4828155d8f Author: Eli Zaretskii Date: Sat May 18 07:56:54 2024 -0400 Merge from origin/emacs-29 a4828155d8f ; * doc/lispintro/emacs-lisp-intro.texi (nthcdr): Whitesp... df1a9e42ba4 Document :box attribute caveats when used on display strings ca17bc8dd0b Improve documentation of 'movemail' d47aa33bcdb Replace incorrect link in Rmail chapter of Emacs manual 35138b90dd2 ; * doc/lispref/parsing.texi (Parsing Program Source): Im... 3dd09516c9a ; Improve documentation of 'set-fontset-font' 042b58b5ff4 ; * doc/emacs/search.texi (Word Search): Add index entry. 60b1768dc50 ; * src/window.c (Fwindow_scroll_bars): Doc fix. commit a4828155d8f2b5dc379dd20f17cb478b63425b64 (refs/remotes/origin/emacs-29) Author: Eli Zaretskii Date: Sat May 18 14:38:29 2024 +0300 ; * doc/lispintro/emacs-lisp-intro.texi (nthcdr): Whitespace (bug#71033). diff --git a/doc/lispintro/emacs-lisp-intro.texi b/doc/lispintro/emacs-lisp-intro.texi index 19777bf8ab7..4649cd59962 100644 --- a/doc/lispintro/emacs-lisp-intro.texi +++ b/doc/lispintro/emacs-lisp-intro.texi @@ -7193,7 +7193,7 @@ the @samp{@result{}} shows what is returned. @smallexample @group (cdr '(pine fir oak maple)) - @result{}(fir oak maple) + @result{} (fir oak maple) @end group @group @@ -7203,7 +7203,7 @@ the @samp{@result{}} shows what is returned. @group (cdr '(oak maple)) - @result{}(maple) + @result{} (maple) @end group @group commit 2e862f81a355435fb7e837ffebee2f657c26ff23 Author: Jimmy Aguilar Mena Date: Wed May 15 15:10:02 2024 +0200 Add support for Rust compilation messages * etc/compilation.txt (Rust): Add Rust/cargo examples. * lisp/progmodes/compile.el (compilation-error-regexp-alist-alist): Add rust/cargo error and warning patterns. (Bug#70794) diff --git a/etc/compilation.txt b/etc/compilation.txt index 05f0829864c..44388e1f197 100644 --- a/etc/compilation.txt +++ b/etc/compilation.txt @@ -523,6 +523,45 @@ NoMethodError: undefined method `not_exists' for nil:NilClass 4 tests, 3 assertions, 3 failures, 1 errors +* Rust + +symbol: cargo + +The [] part is optional, and the file names are always relative to +project's root. + +error[E0425]: cannot find function `ruun` in module `broot::cli` + --> src/main.rs:6:23 + | +6 | match broot::cli::ruun() { + | ^^^^ help: a function with a similar name exists: `run` + | + ::: /tmp/broot/src/cli/mod.rs:49:1 + | +49 | pub fn run() -> Result, ProgramError> { + | -------------------------------------------------------- similarly + named function `run` defined here + +error: cannot find macro `deebug` in this scope + --> src/main.rs:5:5 + | +5 | deebug!("env::args(): {:#?}", std::env::args().collect::>()); + | ^^^^^^ help: a macro with a similar name exists: `debug` + | + ::: /home/ergo/.cargo/registry/src/index.crates.io-6f17d22bba15001f/log-0.4.21/src/macros.rs:154:1 + | +154 | macro_rules! debug { + | ------------------ similarly named macro `debug` defined here + +warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` + --> src/main.rs:3:1 + | +3 | #[feature(proc_macro_diagnostic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(unused_attributes)]` on by default + + * RXP symbol: rxp diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el index b18eb81fee1..2e4eb11811a 100644 --- a/lisp/progmodes/compile.el +++ b/lisp/progmodes/compile.el @@ -224,6 +224,13 @@ of[ \t]+\"?\\([a-zA-Z]?:?[^\":\n]+\\)\"?:" 3 2 nil (1)) \\(?: characters? \\([0-9]+\\)-?\\([0-9]+\\)?:\\)?\\([ \n]Warning\\(?: [0-9]+\\)?:\\)?\\)" 2 (3 . 4) (5 . 6) (7)) + (cargo + "\\(?:\\(?4:error\\)\\|\\(?5:warning\\)\\):[^\0]+?--> \\(?1:[^:]+\\):\\(?2:[[:digit:]]+\\):\\(?3:[[:digit:]]+\\)" + 1 2 3 (5) + nil + (5 compilation-warning-face) + (4 compilation-error-face)) + (cmake "^CMake \\(?:Error\\|\\(Warning\\)\\) at \\(.*\\):\\([1-9][0-9]*\\) ([^)]+):$" 2 3 nil (1)) commit a019d2bd56818046854345922ad805f3212cd116 Author: Tony Zorman Date: Sun Oct 15 16:51:00 2023 +0200 use-package: Add ':ignored-files' support to ':vc' keyword * lisp/use-package/use-package-core.el (use-package-split-when): New utility function to split a list whenever a specified predicate returns t. (use-package-vc-valid-keywords): A new defconst to gather all allowed keywords. (use-package-normalize--vc-arg): Properly normalize the ':ignored-files' keyword, in that the following are all valid ways of entering files: :ignored-files "a" :ignored-files ("a") :ignored-files "a" "b" "c" :ignored-files ("a" "b" "c") (use-package-normalize/:vc): Adjust normalization, now that we do not necessarily receive a valid plist as an input. (Bug#66567) * test/lisp/use-package/use-package-tests.el (use-package-test-normalize/:vc): Add tests for ':ignored-files' keyword. diff --git a/lisp/use-package/use-package-core.el b/lisp/use-package/use-package-core.el index 65640054c40..bb12c3c4f2b 100644 --- a/lisp/use-package/use-package-core.el +++ b/lisp/use-package/use-package-core.el @@ -535,6 +535,24 @@ This is in contrast to merely setting it to 0." (let ((xs (use-package-split-list (apply-partially #'eq key) lst))) (cons (car xs) (use-package-split-list-at-keys key (cddr xs)))))) +(defun use-package-split-when (pred xs) + "Repeatedly split a list according to PRED. +Split XS every time PRED returns t. Keep the delimiters, and +arrange the result in an alist. For example: + + (use-package-split-when #\\='keywordp \\='(:a 1 :b 2 3 4 :c 5)) + ;; => \\='((:a 1) (:b 2 3 4) (:c 5)) + + (use-package-split-when (lambda (x) (> x 2)) \\='(10 1 3 2 4 -1 8 9)) + ;; => \\='((10 1) (3 2) (4 -1) (8) (9))" + (unless (seq-empty-p xs) + (pcase-let* ((`(,first . ,rest) (if (funcall pred (car xs)) + (cons (car xs) (cdr xs)) + (use-package-split-list pred xs))) + (`(,val . ,recur) (use-package-split-list pred rest))) + (cons (cons first val) + (use-package-split-when pred recur))))) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;; Keywords @@ -1648,6 +1666,12 @@ Also see the Info node `(use-package) Creating an extension'." (push `(use-package-vc-install ',arg ,local-path) body)) ; runtime body)) +(defconst use-package-vc-valid-keywords + '( :url :branch :lisp-dir :main-file :vc-backend :rev + :shell-command :make :ignored-files) + "Valid keywords for the `:vc' keyword, see the Info +node `(emacs)Fetching Package Sources'.") + (defun use-package-normalize--vc-arg (arg) "Normalize possible arguments to the `:vc' keyword. ARG is a cons-cell of approximately the form that @@ -1669,24 +1693,27 @@ indicating the latest commit) revision." (:newest nil) (_ (ensure-string v)))) (:vc-backend (ensure-symbol v)) + (:ignored-files (if (listp v) v (list v))) (_ (ensure-string v))))) - (pcase-let ((valid-kws '( :url :branch :lisp-dir :main-file :vc-backend :rev - :shell-command :make)) - (`(,name . ,opts) arg)) + (pcase-let* ((`(,name . ,opts) arg)) (if (stringp opts) ; (NAME . VERSION-STRING) ? (list name opts) - ;; Error handling - (cl-loop for (k _) on opts by #'cddr - if (not (member k valid-kws)) - do (use-package-error - (format "Keyword :vc received unknown argument: %s. Supported keywords are: %s" - k valid-kws))) - ;; Actual normalization - (list name - (cl-loop for (k v) on opts by #'cddr - if (not (eq k :rev)) - nconc (list k (normalize k v))) - (normalize :rev (plist-get opts :rev))))))) + (let ((opts (use-package-split-when + (lambda (el) + (seq-contains-p use-package-vc-valid-keywords el)) + opts))) + ;; Error handling + (cl-loop for (k . _) in opts + if (not (member k use-package-vc-valid-keywords)) + do (use-package-error + (format "Keyword :vc received unknown argument: %s. Supported keywords are: %s" + k use-package-vc-valid-keywords))) + ;; Actual normalization + (list name + (cl-loop for (k . v) in opts + if (not (eq k :rev)) + nconc (list k (normalize k (if (length= v 1) (car v) v)))) + (normalize :rev (car (alist-get :rev opts))))))))) (defun use-package-normalize/:vc (name _keyword args) "Normalize possible arguments to the `:vc' keyword. @@ -1702,9 +1729,9 @@ node `(use-package) Creating an extension'." ((or 'nil 't) (list name)) ; guess name ((pred symbolp) (list arg)) ; use this name ((pred stringp) (list name arg)) ; version string + guess name - ((pred plistp) ; plist + guess name + (`(,(pred keywordp) . ,(pred listp)) ; list + guess name (use-package-normalize--vc-arg (cons name arg))) - (`(,(pred symbolp) . ,(or (pred plistp) ; plist/version string + name + (`(,(pred symbolp) . ,(or (pred listp) ; list/version string + name (pred stringp))) (use-package-normalize--vc-arg arg)) (_ (use-package-error "Unrecognized argument to :vc.\ diff --git a/test/lisp/use-package/use-package-tests.el b/test/lisp/use-package/use-package-tests.el index d1e68c2a790..76de29be471 100644 --- a/test/lisp/use-package/use-package-tests.el +++ b/test/lisp/use-package/use-package-tests.el @@ -2014,7 +2014,15 @@ (should (equal '(foo) (use-package-normalize/:vc 'foo :vc nil))) (should (equal '(bar) - (use-package-normalize/:vc 'foo :vc '(bar))))) + (use-package-normalize/:vc 'foo :vc '(bar)))) + (should (equal + '(foo (:ignored-files ("a" "b" "c")) :last-release) + (use-package-normalize/:vc 'foo :vc '((:ignored-files "a" "b" "c"))))) + (should (equal + (use-package-normalize/:vc 'foo :vc '((:ignored-files "a"))) + (use-package-normalize/:vc 'foo :vc '((:ignored-files ("a")))))) + (should (equal (use-package-normalize/:vc 'foo :vc '((:ignored-files "a" "b" "c"))) + (use-package-normalize/:vc 'foo :vc '((:ignored-files ("a" "b" "c"))))))) ;; Local Variables: ;; no-byte-compile: t commit 426176c75e5337762b185818942c439a93e3d9ef Author: Tony Zorman Date: Sun Oct 15 16:50:00 2023 +0200 use-package: Update list of valid :vc keywords * lisp/use-package/use-package-core.el: Add ':shell-command' and ':make' to valid keywords. (Bug#66567) diff --git a/lisp/use-package/use-package-core.el b/lisp/use-package/use-package-core.el index ba2e93c97e9..65640054c40 100644 --- a/lisp/use-package/use-package-core.el +++ b/lisp/use-package/use-package-core.el @@ -1670,7 +1670,8 @@ indicating the latest commit) revision." (_ (ensure-string v)))) (:vc-backend (ensure-symbol v)) (_ (ensure-string v))))) - (pcase-let ((valid-kws '(:url :branch :lisp-dir :main-file :vc-backend :rev)) + (pcase-let ((valid-kws '( :url :branch :lisp-dir :main-file :vc-backend :rev + :shell-command :make)) (`(,name . ,opts) arg)) (if (stringp opts) ; (NAME . VERSION-STRING) ? (list name opts) commit 82a31e27e6ceed17a116286d2f0f9810be2e1772 Author: Eli Zaretskii Date: Sat May 18 12:55:34 2024 +0300 Fix printing the result by 'eval-print-last-sexp' * lisp/progmodes/elisp-mode.el (elisp--eval-last-sexp): Record the desired output stream before evaluating the expression. (Bug#70931) diff --git a/lisp/progmodes/elisp-mode.el b/lisp/progmodes/elisp-mode.el index 84814c9eaac..7d0312eb2a4 100644 --- a/lisp/progmodes/elisp-mode.el +++ b/lisp/progmodes/elisp-mode.el @@ -1557,13 +1557,16 @@ character)." (pcase-let* ((`(,insert-value ,no-truncate ,char-print-limit) (eval-expression-get-print-arguments eval-last-sexp-arg-internal))) - ;; Setup the lexical environment if lexical-binding is enabled. - (elisp--eval-last-sexp-print-value - (eval (macroexpand-all - (eval-sexp-add-defvars - (elisp--eval-defun-1 (macroexpand (elisp--preceding-sexp))))) - lexical-binding) - (if insert-value (current-buffer) t) no-truncate char-print-limit))) + ;; The expression might change to a different buffer, so record the + ;; desired output stream now. + (let ((output (if insert-value (current-buffer) t))) + ;; Setup the lexical environment if lexical-binding is enabled. + (elisp--eval-last-sexp-print-value + (eval (macroexpand-all + (eval-sexp-add-defvars + (elisp--eval-defun-1 (macroexpand (elisp--preceding-sexp))))) + lexical-binding) + output no-truncate char-print-limit)))) (defun elisp--eval-last-sexp-print-value (value output &optional no-truncate char-print-limit) commit be03dda5b0fc55e989bfa707c73f1cc990e24c3b Author: Jared Finder Date: Fri Jan 26 15:44:12 2024 -0800 Adding window-tool-bar package (bug#68765). * lisp/window-tool-bar.el: New file. diff --git a/lisp/window-tool-bar.el b/lisp/window-tool-bar.el new file mode 100644 index 00000000000..640deccdd61 --- /dev/null +++ b/lisp/window-tool-bar.el @@ -0,0 +1,491 @@ +;;; window-tool-bar.el --- Add tool bars inside windows -*- lexical-binding: t -*- + +;; Copyright (C) 2023-2024 Free Software Foundation, Inc. + +;; Author: Jared Finder +;; Created: Nov 21, 2023 +;; Version: 0.2 +;; Keywords: mouse +;; Package-Requires: ((emacs "29.1")) + +;; This is a GNU ELPA :core package. Avoid adding functionality that +;; is not available in the version of Emacs recorded above or any of +;; the package dependencies. + +;; This file is part of GNU Emacs. + +;; 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 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 +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: +;; +;; This package puts a tool bar in each window. This allows you to see +;; multiple tool bars simultaneously directly next to the buffer it +;; acts on which feels much more intuitive. Emacs "browsing" modes +;; generally have sensible tool bars, for example: *info*, *help*, and +;; *eww* have them. +;; +;; It does this while being mindful of screen real estate. Most modes +;; do not provide a custom tool bar, and this package does not show the +;; default tool bar. This means that for most buffers there will be no +;; space taken up. Furthermore, you can put this tool bar in the mode +;; line or tab line if you want to share it with existing content. +;; +;; To get the default behavior, run (global-window-tool-bar-mode 1) or +;; enable via M-x customize-group RET window-tool-bar RET. This uses +;; the per-window tab line to show the tool bar. +;; +;; If you want to share space with an existing tab line, mode line, or +;; header line, add (:eval (window-tool-bar-string)) to +;; `tab-line-format', `mode-line-format', or `header-line-format'. + +;;; Known issues: +;; +;; On GNU Emacs 29.1, terminals dragging to resize windows will error +;; with message " is undefined". This is a +;; bug in GNU Emacs, +;; . +;; +;; On GNU Emacs 29, performance in terminals is lower than on +;; graphical frames. This is due to a workaround, see "Workaround for +;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=68334", below. + +;;; Todo: +;; +;; Not all features planned are implemented yet. Eventually I would +;; like to also generally make tool bars better. +;; +;; Targeting 0.3: +;; * Properly support reamining less frequently used tool bar item specs. From +;; `parse_tool_bar_item': +;; * :visible +;; * :filter +;; * :button +;; * :wrap +;; * Add display customization similar to `tool-bar-style'. +;; +;; Targeting 1.0: +;; +;; * Clean up Emacs tool bars +;; * Default: Remove default tool-bar entirely +;; * grep, vc: Remove default tool-bar inherited +;; * info: Remove Next / Prev / Up, which is already in the header +;; * smerge: Add tool bar for next/prev +;; +;; Post 1.0 work: +;; +;; * Show keyboard shortcut on help text. +;; +;; * Add a bit more documentation. +;; * Add customization option: ignore-default-tool-bar-map +;; * Make tab-line dragging resize the window + +;;; Code: + +(require 'mwheel) +(require 'tab-line) +(require 'tool-bar) + +;;; Benchmarking code +;; +;; Refreshing the tool bar is computationally simple, but generates a +;; lot of garbage. So this benchmarking focuses on garbage +;; generation. Since it has to run after most commands, generating +;; significantly more garbage will cause noticeable performance +;; degration. +;; +;; The refresh has two steps: +;; +;; Step 1: Look up the map. +;; Step 2: Generate a Lisp string using text properties for the tool +;; bar string. +;; +;; Additionally, we keep track of the percentage of commands that +;; acutally created a refresh. +(defvar window-tool-bar--memory-use-delta-step1 (make-list 7 0) + "Absolute delta of memory use counters during step 1. +This is a list in the same structure as `memory-use-counts'.") +(defvar window-tool-bar--memory-use-delta-step2 (make-list 7 0) + "Absolute delta of memory use counters during step 2. +This is a list in the same structure as `memory-use-counts'.") +(defvar window-tool-bar--refresh-done-count 0 + "Number of tool bar string refreshes run. +The total number of requests is the sum of this and +`window-tool-bar--refresh-skipped-count'.") +(defvar window-tool-bar--refresh-skipped-count 0 + "Number of tool bar string refreshes that were skipped. +The total number of requests is the sum of this and +`window-tool-bar--refresh-done-count'.") + +(defun window-tool-bar--memory-use-avg-step1 () + "Return average memory use delta during step 1." + (mapcar (lambda (elt) (/ (float elt) window-tool-bar--refresh-done-count)) + window-tool-bar--memory-use-delta-step1)) + +(defun window-tool-bar--memory-use-avg-step2 () + "Return average memory use delta during step 2." + (mapcar (lambda (elt) (/ (float elt) window-tool-bar--refresh-done-count)) + window-tool-bar--memory-use-delta-step2)) + +(declare-function time-stamp-string "time-stamp") + +(defun window-tool-bar-debug-show-memory-use () + "Development-only command to show memory used by `window-tool-bar-string'." + (interactive) + (require 'time-stamp) + (save-selected-window + (pop-to-buffer "*WTB Memory Report*") + (unless (derived-mode-p 'special-mode) + (special-mode)) + + (goto-char (point-max)) + (let ((inhibit-read-only t)) + (insert (propertize (concat "Function: window-tool-bar-string " + (time-stamp-string)) + 'face 'underline 'font-lock-face 'underline) + "\n\n") + (window-tool-bar--insert-memory-use + "Step 1" (window-tool-bar--memory-use-avg-step1)) + (window-tool-bar--insert-memory-use + "Step 2" (window-tool-bar--memory-use-avg-step2)) + (insert (format "Refresh count %d\n" window-tool-bar--refresh-done-count) + (format "Refresh executed percent %.2f\n" + (/ (float window-tool-bar--refresh-done-count) + (+ window-tool-bar--refresh-done-count + window-tool-bar--refresh-skipped-count))) + "\n")))) + +(defun window-tool-bar--insert-memory-use (label avg-memory-use) + "Insert memory use into current buffer. + +LABEL is a prefix string to be in front of the data. +AVG-MEMORY-USE is a list of averages, with the same meaning as +`memory-use-counts'." + (let* ((label-len (length label)) + (padding (make-string label-len ?\s))) + (cl-loop for usage in avg-memory-use + for usage-label in '("Conses" "Floats" "Vector cells" "Symbols" + "String chars" "Intervals" "Strings") + for idx from 0 + do (insert (format "%s %8.2f %s\n" + (if (= idx 0) label padding) + usage + usage-label))))) + +(defgroup window-tool-bar nil + "Tool bars per-window." + :group 'convenience + :prefix "window-tool-bar-") + +(defvar-keymap window-tool-bar--button-keymap + :doc "Keymap used by `window-tool-bar--keymap-entry-to-string'." + "" 'mouse-face + ;; Follow link on all clicks of mouse-1 and mouse-2 since the tool + ;; bar is not a place the point can travel to. + " " #'window-tool-bar--call-button + " " #'window-tool-bar--call-button + " " #'window-tool-bar--call-button + " " #'window-tool-bar--call-button + " " #'window-tool-bar--call-button + " " #'window-tool-bar--call-button + + ;; Mouse down events do nothing. A binding is needed so isearch + ;; does not exit when the tab bar is clicked. + " " #'window-tool-bar--ignore + " " #'window-tool-bar--ignore + " " #'window-tool-bar--ignore + " " #'window-tool-bar--ignore + " " #'window-tool-bar--ignore + " " #'window-tool-bar--ignore) +(fset 'window-tool-bar--button-keymap window-tool-bar--button-keymap) ; So it can be a keymap property + +;; Register bindings that stay in isearch. Technically, these +;; commands don't pop up a menu but they act very similar in that they +;; are caused by mouse input and may call commands via +;; `call-interactively'. +(push 'window-tool-bar--call-button isearch-menu-bar-commands) +(push 'window-tool-bar--ignore isearch-menu-bar-commands) + +(defvar-local window-tool-bar-string--cache nil + "Cache for previous result of `window-tool-bar-string'.") + +;;;###autoload +(defun window-tool-bar-string () + "Return a (propertized) string for the tool bar. + +This is for when you want more customizations than +`window-tool-bar-mode' provides. Commonly added to the variable +`tab-line-format', `header-line-format', or `mode-line-format'" + (if (or (null window-tool-bar-string--cache) + (window-tool-bar--last-command-triggers-refresh-p)) + (let* ((mem0 (memory-use-counts)) + (toolbar-menu (window-tool-bar--get-keymap)) + (mem1 (memory-use-counts)) + (result (mapconcat #'window-tool-bar--keymap-entry-to-string + (cdr toolbar-menu) ;Skip 'keymap + ;; Without spaces between the text, hovering + ;; highlights all adjacent buttons. + (if (window-tool-bar--use-images) + (propertize " " 'invisible t) + " "))) + (mem2 (memory-use-counts))) + (cl-mapl (lambda (l-init l0 l1) + (cl-incf (car l-init) (- (car l1) (car l0)))) + window-tool-bar--memory-use-delta-step1 mem0 mem1) + (cl-mapl (lambda (l-init l1 l2) + (cl-incf (car l-init) (- (car l2) (car l1)))) + window-tool-bar--memory-use-delta-step2 mem1 mem2) + + (setf window-tool-bar-string--cache + (concat + ;; The tool bar face by default puts boxes around the + ;; buttons. However, this box is not displayed if the + ;; box starts at the leftmost pixel of the tab-line. + ;; Add a single space in this case so the box displays + ;; correctly. + (and (display-supports-face-attributes-p + '(:box (line-width 1))) + (propertize " " 'display '(space :width (1)))) + result)) + (cl-incf window-tool-bar--refresh-done-count)) + (cl-incf window-tool-bar--refresh-skipped-count)) + + window-tool-bar-string--cache) + +(defconst window-tool-bar--graphical-separator + (concat + (propertize " " 'display '(space :width (4))) + (propertize " " 'display '(space :width (1) face (:inverse-video t))) + (propertize " " 'display '(space :width (4))))) + +(defun window-tool-bar--keymap-entry-to-string (menu-item) + "Convert MENU-ITEM into a (propertized) string representation. + +MENU-ITEM is a menu item to convert. See info node (elisp)Tool Bar." + (pcase-exhaustive menu-item + ;; Separators + ((or `(,_ "--") + `(,_ menu-item ,(and (pred stringp) + (pred (string-prefix-p "--"))))) + (if (window-tool-bar--use-images) + window-tool-bar--graphical-separator + "|")) + + ;; Menu item, turn into propertized string button + (`(,key menu-item ,name-expr ,binding . ,plist) + (when binding ; If no binding exists, then button is hidden. + (let* ((name (eval name-expr)) + (str (upcase-initials (or (plist-get plist :label) + (string-trim-right name "\\.+")))) + (len (length str)) + (enable-form (plist-get plist :enable)) + (enabled (or (not enable-form) + (eval enable-form)))) + (if enabled + (add-text-properties 0 len + '(mouse-face window-tool-bar-button-hover + keymap window-tool-bar--button-keymap + face window-tool-bar-button) + str) + (put-text-property 0 len + 'face + 'window-tool-bar-button-disabled + str)) + (when-let ((spec (and (window-tool-bar--use-images) + (plist-get menu-item :image)))) + (put-text-property 0 len + 'display + (append spec + (if enabled '(:margin 2 :ascent center) + '(:margin 2 :ascent center + :conversion disabled))) + str)) + (put-text-property 0 len + 'help-echo + (or (plist-get plist :help) name) + str) + (put-text-property 0 len 'tool-bar-key key str) + str))))) + +(defun window-tool-bar--call-button () + "Call the button that was clicked on in the tab line." + (interactive) + (when (mouse-event-p last-command-event) + (let ((posn (event-start last-command-event))) + ;; Commands need to execute with the right buffer and window + ;; selected. The selection needs to be permanent for isearch. + (select-window (posn-window posn)) + (let* ((str (posn-string posn)) + (key (get-text-property (cdr str) 'tool-bar-key (car str))) + (cmd (lookup-key (window-tool-bar--get-keymap) (vector key)))) + (call-interactively cmd))))) + +(defun window-tool-bar--ignore () + "Internal command so isearch does not exit on button-down events." + (interactive) + nil) + +(defvar window-tool-bar--ignored-event-types + (let ((list (list 'mouse-movement 'pinch + 'wheel-down 'wheel-up 'wheel-left 'wheel-right + mouse-wheel-down-event mouse-wheel-up-event + mouse-wheel-left-event mouse-wheel-right-event + (bound-and-true-p mouse-wheel-down-alternate-event) + (bound-and-true-p mouse-wheel-up-alternate-event) + (bound-and-true-p mouse-wheel-left-alternate-event) + (bound-and-true-p mouse-wheel-right-alternate-event)))) + (delete-dups (delete nil list))) + "Cache for `window-tool-bar--last-command-triggers-refresh-p'.") + +(defun window-tool-bar--last-command-triggers-refresh-p () + "Test if the recent command or event should trigger a tool bar refresh." + (let ((type (event-basic-type last-command-event))) + (and + ;; Assume that key presses and button presses are the only user + ;; interactions that can alter the tool bar. Specifically, this + ;; excludes mouse movement, mouse wheel scroll, and pinch. + (not (member type window-tool-bar--ignored-event-types)) + ;; Assume that any command that triggers shift select can't alter + ;; the tool bar. This excludes pure navigation commands. + (not (window-tool-bar--command-triggers-shift-select-p last-command)) + ;; Assume that self-insert-command won't alter the tool bar. + ;; This is the most commonly executed command. + (not (eq last-command 'self-insert-command))))) + +(defun window-tool-bar--command-triggers-shift-select-p (command) + "Test if COMMAND would trigger shift select." + (let* ((form (interactive-form command)) + (spec (car-safe (cdr-safe form)))) + (and (eq (car-safe form) 'interactive) + (stringp spec) + (seq-position spec ?^)))) + +;;;###autoload +(define-minor-mode window-tool-bar-mode + "Toggle display of the tool bar in the tab line of the current buffer." + :global nil + (let ((should-display (and window-tool-bar-mode + (not (eq tool-bar-map + (default-value 'tool-bar-map))))) + (default-value '(:eval (window-tool-bar-string)))) + + ;; Preserve existing tab-line set outside of this mode + (if (or (null tab-line-format) + (equal tab-line-format default-value)) + (if should-display + (setq tab-line-format default-value) + (setq tab-line-format nil)) + (message + "tab-line-format set outside of window-tool-bar-mode, currently `%S'" + tab-line-format)))) + +;;;###autoload +(define-globalized-minor-mode global-window-tool-bar-mode + window-tool-bar-mode window-tool-bar--turn-on + :group 'window-tool-bar + (add-hook 'isearch-mode-hook #'window-tool-bar--turn-on) + (add-hook 'isearch-mode-end-hook #'window-tool-bar--turn-on)) + +(defvar window-tool-bar--allow-images t + "Internal debug flag to force text mode.") + +(defun window-tool-bar--use-images () + "Internal function. +Respects `window-tool-bar--allow-images' as well as frame +capabilities." + (and window-tool-bar--allow-images + (display-images-p))) + +;;; Display styling: +(defface window-tool-bar-button + '((default + :inherit tab-line) + (((class color) (min-colors 88) (supports :box t)) + :box (:line-width -1 :style released-button) + :background "grey85") + ;; If the box is not supported, dim the button background a bit. + (((class color) (min-colors 88)) + :background "grey70") + (t + :inverse-video t)) + "Face used for buttons when the mouse is not hovering over the button." + :group 'window-tool-bar) + +(defface window-tool-bar-button-hover + '((default + :inherit tab-line) + (((class color) (min-colors 88)) + :box (:line-width -1 :style released-button) + :background "grey95") + (t + :inverse-video t)) + "Face used for buttons when the mouse is hovering over the button." + :group 'window-tool-bar) + +(defface window-tool-bar-button-disabled + '((default + :inherit tab-line) + (((class color) (min-colors 88)) + :box (:line-width -1 :style released-button) + :background "grey50" + :foreground "grey70") + (t + :inverse-video t + :background "brightblack")) + "Face used for buttons when the button is disabled." + :group 'window-tool-bar) + +;;; Workaround for https://debbugs.gnu.org/cgi/bugreport.cgi?bug=68334. +(defun window-tool-bar--get-keymap () + "Return the tool bar keymap." + (let ((tool-bar-always-show-default nil)) + (if (and (version< emacs-version "30") + (not (window-tool-bar--use-images))) + ;; This code path is a less efficient workaround. + (window-tool-bar--make-keymap-1) + (keymap-global-lookup "")))) + +(declare-function image-mask-p "image.c" (spec &optional frame)) + +(defun window-tool-bar--make-keymap-1 () + "Patched copy of `tool-bar-make-keymap-1'." + (mapcar (lambda (bind) + (let (image-exp plist) + (when (and (eq (car-safe (cdr-safe bind)) 'menu-item) + ;; For the format of menu-items, see node + ;; `Extended Menu Items' in the Elisp manual. + (setq plist (nthcdr (if (consp (nth 4 bind)) 5 4) + bind)) + (setq image-exp (plist-get plist :image)) + (consp image-exp) + (not (eq (car image-exp) 'image)) + (fboundp (car image-exp))) + (let ((image (and (display-images-p) + (eval image-exp)))) + (unless (and image (image-mask-p image)) + (setq image (append image '(:mask heuristic)))) + (setq bind (copy-sequence bind) + plist (nthcdr (if (consp (nth 4 bind)) 5 4) + bind)) + (plist-put plist :image image))) + bind)) + tool-bar-map)) + +(defun window-tool-bar--turn-on () + "Internal function called by `global-window-tool-bar-mode'." + (when global-window-tool-bar-mode + (window-tool-bar-mode 1))) + +(provide 'window-tool-bar) + +;;; window-tool-bar.el ends here commit da325ff7b29b0becdd1356021428fa100d240ec4 Author: Jared Finder Date: Fri Jan 26 10:08:30 2024 -0800 Add user option to only display default tool bar This works well with `window-tool-bar-mode', to be added in upcoming commit. Then the default tool bar is displayed frame-wide and mode-specific tool bars are displayed in the window that mode is active in. * lisp/tool-bar.el (tool-bar-always-show-default): New user option. (tool-bar--cache-key, tool-bar-make-keymap-1): Return default tool bar when option is set. diff --git a/lisp/tool-bar.el b/lisp/tool-bar.el index 0f645338674..01c65c42324 100644 --- a/lisp/tool-bar.el +++ b/lisp/tool-bar.el @@ -100,7 +100,9 @@ parameter is set to `top', and above the tool bar it is set to (defconst tool-bar-keymap-cache (make-hash-table :test #'equal)) (defsubst tool-bar--cache-key () - (cons (frame-terminal) (sxhash-eq tool-bar-map))) + (cons (frame-terminal) + (sxhash-eq (if tool-bar-always-show-default (default-value 'tool-bar-map) + tool-bar-map)))) (defsubst tool-bar--secondary-cache-key () (cons (frame-terminal) (sxhash-eq secondary-tool-bar-map))) @@ -191,7 +193,9 @@ in which case the value of `tool-bar-map' is used instead." bind)) (plist-put plist :image image))) bind)) - (or map tool-bar-map))) + (or map + (if tool-bar-always-show-default (default-value 'tool-bar-map) + tool-bar-map)))) ;;;###autoload (defun tool-bar-add-item (icon def key &rest props) @@ -378,6 +382,15 @@ the tool bar." (modify-all-frames-parameters (list (cons 'tool-bar-position val)))))) +(defcustom tool-bar-always-show-default nil + "If non-nil, `tool-bar-mode' only shows the default tool bar. +This works well when also using `global-window-tool-bar-mode' to +display buffer-specific tool bars." + :type 'boolean + :group 'frames + :group 'mouse + :version "30.1") + ;; Modifier bar mode. commit fd3ab22a3eec5c3151b0791fc768e555b66e267c Author: Jared Finder Date: Sun May 12 20:35:50 2024 -0700 Inform user when tab-line-mode command makes no change * lisp/tab-line.el (tab-line-mode): Display message when command is run on already altered tab-line-format. diff --git a/lisp/tab-line.el b/lisp/tab-line.el index 6898ba53e02..316c87fb3ad 100644 --- a/lisp/tab-line.el +++ b/lisp/tab-line.el @@ -1124,11 +1124,17 @@ However, return the correct mouse position list if EVENT is a (let ((default-value '(:eval (tab-line-format)))) (if tab-line-mode ;; Preserve the existing tab-line set outside of this mode - (unless tab-line-format - (setq tab-line-format default-value)) + (if (null tab-line-format) + (setq tab-line-format default-value) + (message + "tab-line-format set outside of tab-line-mode, currently `%S'" + tab-line-format)) ;; Reset only values set by this mode - (when (equal tab-line-format default-value) - (setq tab-line-format nil))))) + (if (equal tab-line-format default-value) + (setq tab-line-format nil) + (message + "tab-line-format set outside of tab-line-mode, currently `%S'" + tab-line-format))))) (defcustom tab-line-exclude-modes '(completion-list-mode) commit df1a9e42ba483f2a0e3747abc7edb16818993f13 Author: Eli Zaretskii Date: Sat May 18 12:15:21 2024 +0300 Document :box attribute caveats when used on display strings * doc/lispref/display.texi (Replacing Specs, Face Attributes): Mention special considerations when a display string has a ':box' face attribute identical to the surrounding buffer text. Suggested by JD Smith . (Bug#70637) diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index f20064519fc..869bf15a40a 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2747,6 +2747,11 @@ being pressed. If it is @code{pressed-button}, the box looks like a @code{flat-button} or omitted, a plain 2D box is used. @end table +If you use the @code{:box} face attribute on strings displayed instead +of buffer text via the @code{display} text property, special +considerations might apply if the surrounding buffer text also has the +@code{:box} face attribute. @xref{Replacing Specs}. + @item :inverse-video Whether or not characters should be displayed in inverse video. The value should be @code{t} (yes) or @code{nil} (no). @@ -5266,6 +5271,34 @@ characters get a second string (@code{concat} creates a new string object), so they are replaced with one @samp{A}; and so on. Thus, the ten characters appear as five A's. +@cindex box face attribute, and @code{display} properties +Note: Using @code{:box} face attribute (@pxref{Face Attributes}) on a +replacing @code{display} string that is adjacent to normal text with +the same @code{:box} style can lead to display artifacts when moving +the cursor across the text with this face attribute. These can be +avoided by applying the @code{:box} attribute directly to the text +being replaced, rather than (or in addition to) the @code{display} +string itself. Here's an example: + +@smallexample +@group +;; Causes display artifacts when moving the cursor across text +(progn + (put-text-property 1 2 'display (propertize " [" 'face '(:box t))) + (put-text-property 2 3 'face '(:box t)) + (put-text-property 3 4 'display (propertize "] " 'face '(:box t)))) +@end group + +@group +;; No display artifacts due to `:box' +(progn + (add-text-properties 1 2 '(face (:box t) display " [")) + (put-text-property 2 3 'face '(:box t)) + (add-text-properties 3 4 '(face (:box t) display "] "))) +@end group +@end smallexample + + @node Specified Space @subsection Specified Spaces @cindex spaces, specified height or width commit 4f27d763bbe3312b6039fa59f2874bd8e002d201 Author: Joost Kremers Date: Tue May 7 11:52:27 2024 +0200 Make 'vtable-insert-object' more versatile * lisp/emacs-lisp/vtable.el (vtable-insert-object): Rename argument AFTER-OBJECT to LOCATION; allow use of index to refer to the insertion position; add argument BEFORE. (Bug#70664). * etc/NEWS: * doc/misc/vtable.texi (Interface Functions): Document the change. * test/lisp/emacs-lisp/vtable-tests.el (test-vtable-insert-object): New test. diff --git a/doc/misc/vtable.texi b/doc/misc/vtable.texi index dd5b70cf32f..822b1097cd9 100644 --- a/doc/misc/vtable.texi +++ b/doc/misc/vtable.texi @@ -548,10 +548,20 @@ Remove @var{object} from @var{table}. This also updates the displayed table. @end defun -@defun vtable-insert-object table object &optional after-object -Insert @var{object} into @var{table}. If @var{after-object}, insert -the object after this object; otherwise append to @var{table}. This -also updates the displayed table. +@defun vtable-insert-object table object &optional location before +Insert @var{object} into @var{table}. @var{location} should be an +object in the table, the new object is inserted after this object, or +before it if @var{before} is non-nil. If @var{location} is @code{nil}, +@var{object} is appended to @var{table}, or prepended if @var{before} is +non-@code{nil}. + +@var{location} can also be an integer, a zero-based index into the +table. In this case, @var{object} is inserted at that index. If the +index is out of range, @var{object} is prepended to @var{table} if the +index is too small, or appended if it is too large. In this case, +@var{before} is ignored. + +This also updates the displayed table. @end defun @defun vtable-update-object table object &optional old-object diff --git a/etc/NEWS b/etc/NEWS index 77b2749fe43..5bf9a2d07c8 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2635,6 +2635,19 @@ this case, would mean repeating the object in the argument list.) When replacing an object with a different one, passing both the new and old objects is still necessary. +** 'vtable-insert-object' can insert "before" or at an index. +The signature of 'vtable-insert-object' has changed and is now: + +(vtable-insert-object table object &optional location before) + +'location' corresponds to the old 'after-object' argument; if 'before' +is non-nil, the new object is inserted before the 'location' object, +making it possible to insert a new object at the top of the +table. (Before, this was not possible.) In addition, 'location' can be +an integer, a (zero-based) index into the table at which the new object +is inserted ('before' is ignored in this case). + + ** JSON --- diff --git a/lisp/emacs-lisp/vtable.el b/lisp/emacs-lisp/vtable.el index d8e5136c666..cb7ea397314 100644 --- a/lisp/emacs-lisp/vtable.el +++ b/lisp/emacs-lisp/vtable.el @@ -348,19 +348,57 @@ This will also remove the displayed line." (when (vtable-goto-object object) (delete-line))))) -(defun vtable-insert-object (table object &optional after-object) - "Insert OBJECT into TABLE after AFTER-OBJECT. -If AFTER-OBJECT is nil (or doesn't exist in the table), insert -OBJECT at the end. +;; FIXME: The fact that the `location' argument of +;; `vtable-insert-object' can be an integer and is then interpreted as +;; an index precludes the use of integers as objects. This seems a very +;; unlikely use-case, so let's just accept this limitation. + +(defun vtable-insert-object (table object &optional location before) + "Insert OBJECT into TABLE at LOCATION. +LOCATION is an object in TABLE. OBJECT is inserted after LOCATION, +unless BEFORE is non-nil, in which case it is inserted before LOCATION. + +If LOCATION is nil, or does not exist in the table, OBJECT is inserted +at the end of the table, or at the beginning if BEFORE is non-nil. + +LOCATION can also be an integer, a (zero-based) index into the table. +OBJECT is inserted at this location. If the index is out of range, +OBJECT is inserted at the beginning (if the index is less than 0) or +end (if the index is too large) of the table. BEFORE is ignored in this +case. + This also updates the displayed table." + ;; FIXME: Inserting an object into an empty vtable currently isn't + ;; possible. `nconc' fails silently (twice), and `setcar' on the cache + ;; raises an error. + (if (null (vtable-objects table)) + (error "[vtable] Cannot insert object into empty vtable")) ;; First insert into the objects. - (let (pos) - (if (and after-object - (setq pos (memq after-object (vtable-objects table)))) - ;; Splice into list. - (setcdr pos (cons object (cdr pos))) - ;; Append. - (nconc (vtable-objects table) (list object)))) + (let ((pos (if location + (if (integerp location) + (prog1 + (nthcdr location (vtable-objects table)) + ;; Do not prepend if index is too large: + (setq before nil)) + (or (memq location (vtable-objects table)) + ;; Prepend if `location' is not found and + ;; `before' is non-nil: + (and before (vtable-objects table)))) + ;; If `location' is nil and `before' is non-nil, we + ;; prepend the new object. + (if before (vtable-objects table))))) + (if (or before ; If `before' is non-nil, `pos' should be, as well. + (and pos (integerp location))) + ;; Add the new object before. + (let ((old-object (car pos))) + (setcar pos object) + (setcdr pos (cons old-object (cdr pos)))) + ;; Otherwise, add the object after. + (if pos + ;; Splice the object into the list. + (setcdr pos (cons object (cdr pos))) + ;; Otherwise, append the object. + (nconc (vtable-objects table) (list object))))) ;; Then adjust the cache and display. (save-excursion (vtable-goto-table table) @@ -372,19 +410,33 @@ This also updates the displayed table." 'face (vtable-face table)) "")) (ellipsis-width (string-pixel-width ellipsis)) - (elem (and after-object - (assq after-object (car cache)))) + (elem (if location ; This binding mirrors the binding of `pos' above. + (if (integerp location) + (nth location (car cache)) + (or (assq location (car cache)) + (and before (caar cache)))) + (if before (caar cache)))) + (pos (memq elem (car cache))) (line (cons object (vtable--compute-cached-line table object)))) - (if (not elem) - ;; Append. - (progn - (setcar cache (nconc (car cache) (list line))) - (vtable-end-of-table)) - ;; Splice into list. - (let ((pos (memq elem (car cache)))) - (setcdr pos (cons line (cdr pos))) - (unless (vtable-goto-object after-object) - (vtable-end-of-table)))) + (if (or before + (and pos (integerp location))) + ;; Add the new object before:. + (let ((old-line (car pos))) + (setcar pos line) + (setcdr pos (cons old-line (cdr pos))) + (unless (vtable-goto-object (car elem)) + (vtable-beginning-of-table))) + ;; Otherwise, add the object after. + (if pos + ;; Splice the object into the list. + (progn + (setcdr pos (cons line (cdr pos))) + (if (vtable-goto-object location) + (forward-line 1) ; Insert *after*. + (vtable-end-of-table))) + ;; Otherwise, append the object. + (setcar cache (nconc (car cache) (list line))) + (vtable-end-of-table))) (let ((start (point))) ;; FIXME: We have to adjust colors in lines below this if we ;; have :row-colors. diff --git a/test/lisp/emacs-lisp/vtable-tests.el b/test/lisp/emacs-lisp/vtable-tests.el index 08fdf1594a4..1d4b0650210 100644 --- a/test/lisp/emacs-lisp/vtable-tests.el +++ b/test/lisp/emacs-lisp/vtable-tests.el @@ -39,4 +39,34 @@ :insert nil))) '(left right left)))) +(ert-deftest test-vtable-insert-object () + (should + (equal (let ((buffer (get-buffer-create " *vtable-test*"))) + (pop-to-buffer buffer) + (erase-buffer) + (let* ((object1 '("Foo" 3)) + (object2 '("Gazonk" 8)) + (table (make-vtable + :columns '("Name" (:name "Rank" :width 5)) + :objects (list object1 object2)))) + (mapc (lambda (args) + (pcase-let ((`(,object ,location ,before) args)) + (vtable-insert-object table object location before))) + `( ; Some correct inputs. + ;; object location before + (("Fizz" 4) ,object1 nil) + (("Bop" 7) ,object2 t) + (("Zat" 5) 2 nil) + (("Dib" 6) 3 t) + (("Wup" 9) nil nil) + (("Quam" 2) nil t) + ;; And some faulty inputs. + (("Yat" 1) -1 nil) ; non-existing index, `before' is ignored. + (("Vop" 10) 100 t) ; non-existing index, `before' is ignored. + (("Jib" 11) ("Bleh" 0) nil) ; non-existing object. + (("Nix" 0) ("Ugh" 0) t) ; non-existing object. + )) + (mapcar #'cadr (vtable-objects table)))) + (number-sequence 0 11)))) + ;;; vtable-tests.el ends here commit ca17bc8dd0b51b6dbacd6e63a97d81488d45ec71 Author: Eli Zaretskii Date: Sat May 18 09:12:54 2024 +0300 Improve documentation of 'movemail' * doc/emacs/rmail.texi (Movemail): Fix the name of the Mailutils manual in the printed version. Add index entries. Move the description of remote mailboxes to... (Remote Mailboxes): ...here, to avoid duplication. diff --git a/doc/emacs/rmail.texi b/doc/emacs/rmail.texi index 6efc610a49d..9c20d30c442 100644 --- a/doc/emacs/rmail.texi +++ b/doc/emacs/rmail.texi @@ -1428,7 +1428,7 @@ encrypted/decrypted text. your Rmail file (@pxref{Rmail Inbox}). When loaded for the first time, Rmail attempts to locate the @command{movemail} program and determine its version. There are two versions of the @command{movemail} program: the -GNU Mailutils version (@pxref{movemail,,,mailutils,GNU Mailutils}), +GNU Mailutils version (@pxref{movemail,,,mailutils,GNU Mailutils Manual}), and an Emacs-specific version that is built and installed unless Emacs was configured @option{--with-mailutils} in effect. The two @command{movemail} versions support the same @@ -1446,7 +1446,7 @@ mailboxes, etc. It is able to access remote mailboxes using the POP3 or IMAP4 protocol, and can retrieve mail from them using a TLS encrypted channel. It also accepts mailbox arguments in @acronym{URL} form. The detailed description of mailbox @acronym{URL}s can be found -in @ref{Mailbox,,,mailutils,GNU Mailutils}. In short, a +in @ref{Mailbox,,,mailutils,GNU Mailutils Manual}. In short, a @acronym{URL} is: @smallexample @@ -1457,6 +1457,8 @@ in @ref{Mailbox,,,mailutils,GNU Mailutils}. In short, a where square brackets denote optional elements. @table @var +@cindex mailbox protocol, @command{movemail} +@cindex format, of @command{movemail} mailbox @item proto Specifies the @dfn{mailbox protocol}, or @dfn{format} to use. The exact semantics of the rest of @acronym{URL} elements depends @@ -1502,23 +1504,13 @@ automatically by @command{movemail}. @item pop @itemx pops -A remote mailbox to be accessed via POP3 protocol. @var{user} -specifies the remote user name to use, @var{pass} may be used to -specify the user password, @var{host-or-file-name} is the name or IP -address of the remote mail server to connect to, and @var{port} is the -port number; e.g., @code{pop://smith:guessme@@remote.server.net:995}. -If the server supports it, @command{movemail} tries to use an -encrypted connection---use the @samp{pops} form to require one. +A remote mailbox to be accessed via POP3 protocol. @xref{Remote +Mailboxes}, for details. @item imap @itemx imaps -A remote mailbox to be accessed via IMAP4 protocol. @var{user} -specifies the remote user name to use, @var{pass} may be used to -specify the user password, @var{host-or-file-name} is the name or IP -address of the remote mail server to connect to, and @var{port} is the -port number; e.g., @code{imap://smith:guessme@@remote.server.net:993}. -If the server supports it, @command{movemail} tries to use an -encrypted connection---use the @samp{imaps} form to require one. +A remote mailbox to be accessed via IMAP4 protocol. @xref{Remote +Mailboxes}, for details. @end table Alternatively, you can specify the file name of the mailbox to use. @@ -1540,6 +1532,7 @@ listed in @code{rmail-movemail-search-path}, then in @code{exec-path} @node Remote Mailboxes @section Retrieving Mail from Remote Mailboxes @pindex movemail +@cindex remote mailboxes, accessing by @command{movemail} Some sites use a method called POP3 for accessing users' inbox data instead of storing the data in inbox files. The Mailutils @@ -1564,8 +1557,9 @@ Additionally, you may specify the password in the mailbox @acronym{URL}: case, @var{password} takes preference over the one set by @code{rmail-remote-password} (see below). This is especially useful if you have several remote mailboxes with different passwords. -If using Mailutils @command{movemail}, you may wish to use -@samp{pops} in place of @samp{pop}. +If using Mailutils @command{movemail} and the server supports +encrypted connections, @command{movemail} tries to use it; specify +@samp{pops:} instead of @samp{pop:} to require such a connection. For backward compatibility, Rmail also supports an alternative way of specifying remote POP3 mailboxes. Specifying an inbox name in the form @@ -1575,12 +1569,14 @@ specifying remote POP3 mailboxes. Specifying an inbox name in the form the machine on which to look for the POP3 server. @cindex IMAP mailboxes - Another method for accessing remote mailboxes is IMAP@. This method is -supported only by the Mailutils @command{movemail}. To specify an IMAP -mailbox in the inbox list, use the following mailbox @acronym{URL}: -@samp{imap://@var{username}[:@var{password}]@@@var{hostname}:@var{port}}. The -@var{password} part is optional, as described above. You may wish to -use @samp{imaps} in place of @samp{imap}. + Another method for accessing remote mailboxes is IMAP@. This method +is supported only by the Mailutils @command{movemail}, and uses the +IMAP4 protocol. To specify an IMAP mailbox in the inbox list, use the +following mailbox @acronym{URL}: +@samp{imap://@var{username}[:@var{password}]@@@var{hostname}:@var{port}}. +The @var{password} part is optional, as described above. If the +server supports it, @command{movemail} tries to use an encrypted +connection---use the @samp{imaps:} form to require one. @vindex rmail-remote-password @vindex rmail-remote-password-required commit d47aa33bcdbd24283f680285f17736bd758ccba9 Author: Jakub Ječmínek Date: Fri May 17 22:07:33 2024 +0200 Replace incorrect link in Rmail chapter of Emacs manual * doc/emacs/rmail.texi (Movemail): Fix cross-reference to a node in the Mailutils manual. (Bug#71018) diff --git a/doc/emacs/rmail.texi b/doc/emacs/rmail.texi index f94708b08ac..6efc610a49d 100644 --- a/doc/emacs/rmail.texi +++ b/doc/emacs/rmail.texi @@ -1428,7 +1428,7 @@ encrypted/decrypted text. your Rmail file (@pxref{Rmail Inbox}). When loaded for the first time, Rmail attempts to locate the @command{movemail} program and determine its version. There are two versions of the @command{movemail} program: the -GNU Mailutils version (@pxref{movemail,,,mailutils,GNU mailutils}), +GNU Mailutils version (@pxref{movemail,,,mailutils,GNU Mailutils}), and an Emacs-specific version that is built and installed unless Emacs was configured @option{--with-mailutils} in effect. The two @command{movemail} versions support the same @@ -1446,8 +1446,7 @@ mailboxes, etc. It is able to access remote mailboxes using the POP3 or IMAP4 protocol, and can retrieve mail from them using a TLS encrypted channel. It also accepts mailbox arguments in @acronym{URL} form. The detailed description of mailbox @acronym{URL}s can be found -@c Note this node seems to be missing in some versions of mailutils.info? -in @ref{URL,,,mailutils,Mailbox URL Formats}. In short, a +in @ref{Mailbox,,,mailutils,GNU Mailutils}. In short, a @acronym{URL} is: @smallexample commit 35138b90dd24cb967a124481ae06f8df14821c04 Author: Eli Zaretskii Date: Fri May 17 19:03:39 2024 +0300 ; * doc/lispref/parsing.texi (Parsing Program Source): Improve indexing. diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi index fbd739b76d5..fc4eed506ea 100644 --- a/doc/lispref/parsing.texi +++ b/doc/lispref/parsing.texi @@ -4,6 +4,7 @@ @c See the file elisp.texi for copying conditions. @node Parsing Program Source @chapter Parsing Program Source +@cindex parsing program source @cindex syntax tree, from parsing program source Emacs provides various ways to parse program source text and produce a commit 3dd09516c9a87f663fefde77befb7d569cbed9f0 Author: Eli Zaretskii Date: Fri May 17 10:18:35 2024 +0300 ; Improve documentation of 'set-fontset-font' * doc/lispref/display.texi (Fontsets): * src/fontset.c (Fset_fontset_font): Doc fix (bug#70993). diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index c6b29e87b3a..f20064519fc 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -4015,6 +4015,14 @@ the charset @code{japanese-jisx0208}: (set-fontset-font t 'japanese-jisx0208 (font-spec :family "Kochi Gothic")) @end smallexample + +Note that this function should generally be called from the user's +init files, and more generally before any of @var{characters} were +displayed in the current Emacs session. That's because for some +scripts, Emacs caches the way they are displayed, and the cached +information includes the font used for them -- once these characters +are displayed once, the cached font will continue to be used +regardless of changes in the fontsets. @end defun @defun char-displayable-p char diff --git a/src/fontset.c b/src/fontset.c index 7af6782a37c..4aa2fb7b2c7 100644 --- a/src/fontset.c +++ b/src/fontset.c @@ -1499,7 +1499,16 @@ Optional 5th argument ADD, if non-nil, specifies how to add FONT-SPEC to the previously set font specifications for CHARACTERS. If it is `prepend', FONT-SPEC is prepended to the existing font specifications. If it is `append', FONT-SPEC is appended. By default, FONT-SPEC -overwrites the previous settings. */) +overwrites the previous settings. + +For reliable results, this function should be called before any +of CHARACTERS were displayed in the current Emacs session. In +particular, if some of CHARACTERS are displayed using character +compositions, those compositions will be cached after they are first +produced, and the cached values include the font used for displaying +the composed characters -- calling this function will not affect the +font recorded in the cache of compositions, thus they will continue +to be shown using the fonts from before the call. */) (Lisp_Object fontset, Lisp_Object characters, Lisp_Object font_spec, Lisp_Object frame, Lisp_Object add) { commit 042b58b5ff4ac4c17e03b25fd2c367c1cf869a99 Author: Eli Zaretskii Date: Thu May 16 18:42:43 2024 +0300 ; * doc/emacs/search.texi (Word Search): Add index entry. diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index e997e1b2fe4..e5338c01a7d 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -784,6 +784,7 @@ matching}) has no effect on them. @vindex eww-search-prefix @cindex Internet search @cindex search Internet for keywords +@cindex web search To search the Web for the text in region, type @kbd{M-s M-w}. This command performs an Internet search for the words in region using the search engine whose @acronym{URL} is specified by the variable commit 60b1768dc50c33a6788a626351f9d902a859b622 Author: Eli Zaretskii Date: Mon May 13 08:00:38 2024 +0300 ; * src/window.c (Fwindow_scroll_bars): Doc fix. diff --git a/src/window.c b/src/window.c index 3a8f864ec69..5301b76fa85 100644 --- a/src/window.c +++ b/src/window.c @@ -8086,9 +8086,18 @@ DEFUN ("window-scroll-bars", Fwindow_scroll_bars, Swindow_scroll_bars, WINDOW must be a live window and defaults to the selected one. Value is a list of the form (WIDTH COLUMNS VERTICAL-TYPE HEIGHT LINES -HORIZONTAL-TYPE PERSISTENT), see `set-window-scroll-bars'. If WIDTH -or HEIGHT is nil or VERTICAL-TYPE or HORIZONTAL-TYPE is t, WINDOW is -using the frame's corresponding value. */) +HORIZONTAL-TYPE PERSISTENT). WIDTH reports the pixel width of the +vertical scroll bar; COLUMNS is the equivalent number of columns. +Similarly, HEIGHT and LINES are the height of the horizontal scroll +bar in pixels and the equivalent number of lines. VERTICAL-TYPE +reports the type of the vertical scroll bar, either left, right, nil, +or t. HORIZONTAL-TYPE reports the type of the horizontal scroll bar, +either bottom, nil or t. PERSISTENT reports the value specified by +the last successful call to `set-window-scroll-bars', or nil if there +was none. + +If WIDTH or HEIGHT is nil or VERTICAL-TYPE or HORIZONTAL-TYPE is t, +WINDOW is using the corresponding value specified for the frame. */) (Lisp_Object window) { struct window *w = decode_live_window (window);