From 64ea1a178c6cb3a436eeb6783237bd603be4f5e4 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 12 Dec 2021 15:50:28 +0800 Subject: [PATCH 01/20] Fix eshell for systems that do not have subprocesses * lisp/eshell/esh-cmd.el (eshell-eval-command): Use `eshell-processp' instead of `processp'. --- lisp/eshell/esh-cmd.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el index a2464ad4a98..213b7ab2893 100644 --- a/lisp/eshell/esh-cmd.el +++ b/lisp/eshell/esh-cmd.el @@ -945,12 +945,12 @@ at the moment are: ;; In that case, unwrap the value before checking the delimiter ;; value. (if (and val - (not (processp val)) + (not (eshell-processp val)) (not (eq val t))) (error "Unmatched delimiter: %S" val) ;; Eshell-command expect a list like () to know if the ;; command should be async or not. - (or (and (processp val) delim) val))))) + (or (and (eshell-processp val) delim) val))))) (defun eshell-resume-command (proc status) "Resume the current command when a process ends." From b5354e989d8ec590ef6160f9241333a7d73628e3 Mon Sep 17 00:00:00 2001 From: Richard Stallman Date: Tue, 7 Dec 2021 23:35:31 -0500 Subject: [PATCH 02/20] Rewrite the "Quitting Windows" section of Emacs Lisp Reference * doc/lispref/windows.texi (Quitting Windows): Rewrite for clarity. (Bug#52328) --- doc/lispref/functions.texi | 7 +- doc/lispref/windows.texi | 210 +++++++++++++++++++++---------------- 2 files changed, 124 insertions(+), 93 deletions(-) diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi index afb9dfcb9ec..c8f3b12080a 100644 --- a/doc/lispref/functions.texi +++ b/doc/lispref/functions.texi @@ -1648,9 +1648,10 @@ function will be interactive and will use the interactive spec of @var{function}. One exception: if the interactive spec of @var{function} is a function (i.e., a @code{lambda} expression or an @code{fbound} symbol rather than an expression or a string), then the interactive -spec of the combined function will be a call to that function with as sole -argument the interactive spec of the original function. To interpret the spec -received as argument, use @code{advice-eval-interactive-spec}. +spec of the combined function will be a call to that function with +the interactive spec of the original function as sole argument. To +interpret the spec received as argument, use +@code{advice-eval-interactive-spec}. Note: The interactive spec of @var{function} will apply to the combined function and should hence obey the calling convention of the combined function diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi index 54a5bce96c1..d988a0ff118 100644 --- a/doc/lispref/windows.texi +++ b/doc/lispref/windows.texi @@ -4185,97 +4185,48 @@ action alist entry (@pxref{Buffer Display Action Alists}). @node Quitting Windows @section Quitting Windows +@cindex quitting windows -When you want to get rid of a window used for displaying a buffer, you -can call @code{delete-window} or @code{delete-windows-on} -(@pxref{Deleting Windows}) to remove that window from its frame. If the -buffer is shown on a separate frame, you might want to call -@code{delete-frame} (@pxref{Deleting Frames}) instead. If, on the other -hand, a window has been reused for displaying the buffer, you might -prefer showing the buffer previously shown in that window, by calling the -function @code{switch-to-prev-buffer} (@pxref{Window History}). -Finally, you might want to either bury (@pxref{Buffer List}) or kill -(@pxref{Killing Buffers}) the window's buffer. +After a command uses @code{display-buffer} to put a buffer on the +screen, the user may decide to hide it and return to the previous +configuration of the Emacs display. We call that @dfn{quitting the +window}. The way to do this is to call @code{quit-window} while the +window used by @code{display-buffer} is the selected window. - The following command uses information on how the window for -displaying the buffer was obtained in the first place, thus attempting -to automate the above decisions for you. +The right way to restore the previous configuration of the display +depends on what was done to the window where the buffer now appears. +It might be right to delete that window, or delete its frame, or just +display another buffer in that window. One complication is that the +user may have changed the window configuration since the act of +displaying that buffer, and it would be undesirable to undo the user's +explicitly requested changes. + +To enable @code{quit-window} to do the right thing, +@code{display-buffer} saves information about what it did in the +window's @code{quit-restore} parameter (@pxref{Window Parameters}). @deffn Command quit-window &optional kill window This command quits @var{window} and buries its buffer. The argument @var{window} must be a live window and defaults to the selected one. With prefix argument @var{kill} non-@code{nil}, it kills the buffer -instead of burying it. It calls the function @code{quit-restore-window} -described next to deal with the window and its buffer. +instead of burying it. @vindex quit-window-hook -The functions in @code{quit-window-hook} are run before doing anything -else. +The function @code{quit-window} first runs @code{quit-window-hook}. +Then it calls the function @code{quit-restore-window}, described next, +which does the hard work. @end deffn +You can get more control by calling @code{quit-restore-window} instead. + @defun quit-restore-window &optional window bury-or-kill This function handles @var{window} and its buffer after quitting. The optional argument @var{window} must be a live window and defaults to -the selected one. The function's behavior is determined by the four -elements of the list specified by @var{window}'s @code{quit-restore} -parameter (@pxref{Window Parameters}). - -The first element of the @code{quit-restore} parameter is one of the -symbols @code{window}, meaning that the window has been specially -created by @code{display-buffer}; @code{frame}, a separate frame has -been created; @code{same}, the window has only ever displayed this -buffer; or @code{other}, the window showed another buffer before. -@code{frame} and @code{window} affect how the window is quit, while -@code{same} and @code{other} affect the redisplay of buffers -previously shown in @var{window}. - -The parameter's second element is either one of the symbols -@code{window} or @code{frame}, or a list whose elements are the buffer -shown in @var{window} before, that buffer's window start and window -point positions, and @var{window}'s height at that time. If that -buffer is still live when @var{window} is quit, then this function may -reuse @var{window} to display it. - -The third element is the window selected at the time the parameter was -created. If this function deletes @var{window}, it subsequently tries -to reselect the window named by that element. - -The fourth element is the buffer whose display caused the creation of -this parameter. This function may delete @var{window} if and only if -it still shows that buffer. - -This function will try to delete @var{window} if and only if (1) the -first element of its @code{quit-restore} parameter is either -@code{window} or @code{frame}, (2) the window has no history of -previously-displayed buffers and (3) the fourth element of the -@code{quit-restore} parameter specifies the buffer currently displayed -in @var{window}. If @var{window} is part of an atomic window -(@pxref{Atomic Windows}), it will try to delete the root of that -atomic window instead. In either case, it tries to avoid signaling an -error when @var{window} cannot be deleted. - -If @var{window} shall be deleted, is the only window on its frame and -there are other frames on that frame's terminal, the value of the -optional argument @var{bury-or-kill} determines how to proceed with -the window. If @var{bury-or-kill} equals @code{kill}, the frame is -deleted unconditionally. Otherwise, the fate of the frame is -determined by calling @code{frame-auto-hide-function} (see below) with -that frame as sole argument. - -If the second element of the @code{quit-restore} parameter is a list -of a buffer, a window start (@pxref{Window Start and End}) and a -window point (@pxref{Window Point}), and that buffer is still live, -the buffer will be displayed, and start and point set accordingly. -If, in addition, @var{window}'s buffer was temporarily resized, this -function will also try to restore the original height of @var{window}. - -Otherwise, if @var{window} was previously used for displaying other -buffers (@pxref{Window History}), the most recent buffer in that -history will be displayed. In either case, if @var{window} is not -deleted, its @code{quit-restore} parameter is reset to @code{nil}. +the selected one. The function takes account of the @var{window}'s +@code{quit-restore} parameter. The optional argument @var{bury-or-kill} specifies how to deal with -@var{window}'s buffer. The following values are handled: +@var{window}'s buffer. The following values are meaningful: @table @code @item nil @@ -4285,25 +4236,106 @@ consequence, if @var{window} is not deleted, invoking @item append This means that if @var{window} is not deleted, its buffer is moved to -the end of @var{window}'s list of previous buffers, so it's less likely -that a future invocation of @code{switch-to-prev-buffer} will switch to -it. Also, it moves the buffer to the end of the frame's buffer list. +the end of @var{window}'s list of previous buffers (@pxref{Window +History}), so it's less likely that future invocations of +@code{switch-to-prev-buffer} will switch to it. Also, it moves the +buffer to the end of the frame's buffer list (@pxref{Buffer List}). @item bury This means that if @var{window} is not deleted, its buffer is removed -from @var{window}'s list of previous buffers. Also, it moves the buffer -to the end of the frame's buffer list. This value provides the most -reliable remedy to not have @code{switch-to-prev-buffer} switch to this -buffer again without killing the buffer. +from @var{window}'s list of previous buffers. Also, it moves the +buffer to the end of the frame's buffer list. This is the most +reliable way to prevent @code{switch-to-prev-buffer} from switching to +this buffer again, short of killing the buffer. @item kill This means to kill @var{window}'s buffer. @end table +The argument @var{bury-or-kill} also specifies what to do with +@var{window}'s frame when @var{window} should be deleted, if it is the +only window on its frame, and there are other frames on that frame's +terminal. If @var{bury-or-kill} equals @code{kill}, it means to +delete the frame. Otherwise, the fate of the frame is determined by +calling @code{frame-auto-hide-function} (see below) with that frame as +sole argument. + +This function always sets @var{window}'s @code{quit-restore} parameter +to @code{nil} unless it deletes the window. +@end defun + +The window @var{window}'s @code{quit-restore} parameter (@pxref{Window +Parameters}) should be @code{nil} or a list of four elements: +@c FIXME: describe what quit-restore-window does if this is nil. + +@lisp +(@var{method} @var{obuffer} @var{owindow} @var{this-buffer}) +@end lisp + +The first element, @var{method}, is one of the four symbols +@code{window}, @code{frame}, @code{same} and @code{other}. +@code{frame} and @code{window} control how to delete @var{window}, +while @code{same} and @code{other} control displaying some other +buffer in it. + +Specifically, @code{window} means that the window has been specially +created by @code{display-buffer}; @code{frame} means that a separate +frame has been created; @code{same}, that the window has only ever +displayed this buffer; @code{other}, that the window showed another +buffer before. + +The second element, @var{obuffer}, is either one of the symbols +@code{window} or @code{frame}, or a list of the form + +@lisp +(@var{prev-buffer} @var{prev-window-start} @var{prev-window-point} @var{height}) +@end lisp + +@noindent +which says which buffer was shown in @var{window} before, that +buffer's window start (@pxref{Window Start and End}) and window point +(@pxref{Window Point}) positions at that time, and +@var{window}'s height at that time. If @var{prev-buffer} is still +live when quitting @var{window}, quitting the window may reuse +@var{window} to display @var{prev-buffer}. + +The third element, @var{owindow}, is the window that was selected +just before the displaying was done. If quitting deletes +@var{window}, it tries to select @var{owindow}. + +The fourth element, @var{this-buffer}, is the buffer whose displaying +set the @code{quit-restore} parameter. Quitting @var{window} may delete +that window only if it still shows that buffer. + +Quitting @var{window} tries to delete it if and only if (1) +@var{method} is either @code{window} or @code{frame}, (2) the window +has no history of previously-displayed buffers and (3) +@var{this-buffer} equals the buffer currently displayed in +@var{window}. If @var{window} is part of an atomic window +(@pxref{Atomic Windows}), quitting will try to delete the root of that +atomic window instead. In either case, it tries to avoid signaling an +error when @var{window} cannot be deleted. + +If @var{obuffer} is a list, and @var{prev-buffer} is still live, +quitting displays @var{prev-buffer} in @var{window} according to the +rest of the elements of @var{obuffer}. This includes resizing the +window to @var{height} if it was temporarily resized to display +@var{this-buffer}. + +Otherwise, if @var{window} was previously used for displaying other +buffers (@pxref{Window History}), the most recent buffer in that +history will be displayed. + +@ignore +@c FIXME: Should we document display-buffer-reuse-window? +If we document display-buffer-record-window, it should be with @defun. +And maybe not here. + + Typically, the display routines run by @code{display-buffer} will set -the @code{quit-restore} window parameter correctly. It's also -possible to set it manually, using the following code for displaying -@var{buffer} in @var{window}: +the @code{quit-restore} window parameter correctly. You can also set +it manually, using the following code for displaying @var{buffer} in +@var{window}: @example @group @@ -4317,11 +4349,10 @@ possible to set it manually, using the following code for displaying Setting the window history to @code{nil} ensures that a future call to @code{quit-window} can delete the window altogether. +@end ignore -@end defun - -The following option specifies how to deal with a frame containing just -one window that should be either quit, or whose buffer should be buried. +The following option specifies a function to do the right thing with a +frame containing one window when quitting that window. @defopt frame-auto-hide-function The function specified by this option is called to automatically hide @@ -4350,7 +4381,6 @@ that frame's @code{auto-hide-function} frame parameter (@pxref{Frame Interaction Parameters}). @end defopt - @node Side Windows @section Side Windows @cindex side windows From ea8422204f1fbd354e4d25b8c99fd4916db87296 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sun, 12 Dec 2021 20:20:51 +0200 Subject: [PATCH 03/20] * make-dist (manifest): Filter out msdos/autogen/* files. --- make-dist | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/make-dist b/make-dist index eb040150d9d..b069130ca61 100755 --- a/make-dist +++ b/make-dist @@ -392,9 +392,11 @@ manifest=MANIFEST # other way when adding or deleting a distributed file while not using Git. # TODO: maybe this should ignore $update, and always update MANIFEST # if .git is present. +# Filter out the files in msdos/autogen/, as they aren't useful in the +# tarball, and get in the way during the build of the MSDOS port. if ( [ $update = yes ] || [ ! -f $manifest ] ) && [ -r .git ]; then echo "Updating $manifest" - git ls-files > $manifest || exit + git ls-files | sed -e '/^msdos\/autogen\//d' > $manifest || exit printf '%s\n' $possibly_non_vc_files $info_files >>$manifest || exit sort -u -o $manifest $manifest || exit fi From 62139aeb42e286b51afe7dd6045ba7f5519593fc Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Sun, 12 Dec 2021 20:25:54 +0200 Subject: [PATCH 04/20] * lisp/tab-bar.el (tab-bar-switch-to-last-tab): Add 'abs' for precautions. https://lists.gnu.org/archive/html/emacs-devel/2021-11/msg01149.html --- lisp/tab-bar.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index cfd766d5495..68d28306dd9 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -1175,7 +1175,7 @@ which means the last tab on the tab bar. For example, `C-u 2 -9' selects the tab before the last tab." (interactive "p") (tab-bar-select-tab (- (length (funcall tab-bar-tabs-function)) - (1- (or arg 1))))) + (1- (abs (or arg 1)))))) (defun tab-bar-switch-to-recent-tab (&optional arg) "Switch to ARGth most recently visited tab. From 9bd3f78645e14fdbaf3a569df5e0a52249c4f90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Le=20Gouguec?= Date: Mon, 13 Dec 2021 05:17:00 +0100 Subject: [PATCH 05/20] Make `M-x run-python' select the window again Interactively, we want M-x run-python to focus the interpreter buffer. The previous code failed in two ways: - the call to 'display-buffer' was not reached if an interpreter was already running, - set-buffer is ineffectual if the interpreter's window is not selected: once Emacs returns to the command loop, the current buffer will revert back to what the selected window contains. * lisp/progmodes/python.el (python-shell-make-comint): Handle the SHOW argument regardless of whether an interpreter buffer exists, and use pop-to-buffer to select the window. (run-python): Delegate buffer management to 'python-shell-make-comint'. * test/lisp/progmodes/python-tests.el (python-tests--run-python-selects-window): Rename from 'python-tests--bug31398', and adjust assertions (bug#52380). --- lisp/progmodes/python.el | 4 ++-- test/lisp/progmodes/python-tests.el | 18 ++++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el index f1c3e75bb73..6357c4f2d3e 100644 --- a/lisp/progmodes/python.el +++ b/lisp/progmodes/python.el @@ -2994,8 +2994,9 @@ killed." (mapconcat #'identity args " "))) (with-current-buffer buffer (inferior-python-mode)) - (when show (display-buffer buffer)) (and internal (set-process-query-on-exit-flag process nil)))) + (when show + (pop-to-buffer proc-buffer-name)) proc-buffer-name)))) ;;;###autoload @@ -3027,7 +3028,6 @@ process buffer for a list of commands.)" (python-shell-make-comint (or cmd (python-shell-calculate-command)) (python-shell-get-process-name dedicated) show))) - (set-buffer buffer) (get-buffer-process buffer))) (defun run-python-internal () diff --git a/test/lisp/progmodes/python-tests.el b/test/lisp/progmodes/python-tests.el index 6ab9c62746e..752a4f0113f 100644 --- a/test/lisp/progmodes/python-tests.el +++ b/test/lisp/progmodes/python-tests.el @@ -5448,15 +5448,21 @@ buffer with overlapping strings." (python-nav-end-of-statement))) (should (eolp)))) -;; After call `run-python' the buffer running the python process is current. -(ert-deftest python-tests--bug31398 () - "Test for https://debbugs.gnu.org/31398 ." +;; Interactively, `run-python' focuses the buffer running the +;; interpreter. +(ert-deftest python-tests--run-python-selects-window () + "Test for bug#31398. See also bug#44421 and bug#52380." (skip-unless (executable-find python-tests-shell-interpreter)) - (let ((buffer (process-buffer (run-python nil nil 'show)))) - (should (eq buffer (current-buffer))) + (let* ((buffer (process-buffer (run-python nil nil 'show))) + (window (get-buffer-window buffer))) + ;; We look at `selected-window' rather than `current-buffer' + ;; because as `(elisp)Current buffer' says, the latter will only + ;; be synchronized with the former when returning to the "command + ;; loop"; until then, `current-buffer' can change arbitrarily. + (should (eq window (selected-window))) (pop-to-buffer (other-buffer)) (run-python nil nil 'show) - (should (eq buffer (current-buffer))))) + (should (eq window (selected-window))))) (ert-deftest python-tests--fill-long-first-line () (should From 3a773cbbf56509b18e3138c47509622d533abf37 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Mon, 13 Dec 2021 02:54:32 +0100 Subject: [PATCH 06/20] * lisp/ielm.el (ielm-header): Show key binding for describe-mode. --- lisp/ielm.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lisp/ielm.el b/lisp/ielm.el index 39820a893a9..0ddd83f1003 100644 --- a/lisp/ielm.el +++ b/lisp/ielm.el @@ -148,7 +148,9 @@ such as `edebug-defun' to work with such inputs." This variable is buffer-local.") (defvar ielm-header - "*** Welcome to IELM *** Type (describe-mode) for help.\n" + (substitute-command-keys + "*** Welcome to IELM *** Type (describe-mode) or press \ +\\[describe-mode] for help.\n") "Message to display when IELM is started.") (defvaralias 'inferior-emacs-lisp-mode-map 'ielm-map) From 38f782f48df3a35c2735707892610325a5cba92d Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Mon, 13 Dec 2021 14:14:19 +0100 Subject: [PATCH 07/20] * lisp/ielm.el (ielm-map): Use defvar-keymap. --- lisp/ielm.el | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/lisp/ielm.el b/lisp/ielm.el index 0ddd83f1003..ec7f010a4d5 100644 --- a/lisp/ielm.el +++ b/lisp/ielm.el @@ -154,24 +154,22 @@ This variable is buffer-local.") "Message to display when IELM is started.") (defvaralias 'inferior-emacs-lisp-mode-map 'ielm-map) -(defvar ielm-map - (let ((map (make-sparse-keymap))) - (define-key map "\t" 'ielm-tab) - (define-key map "\C-m" 'ielm-return) - (define-key map "\e\C-m" 'ielm-return-for-effect) - (define-key map "\C-j" 'ielm-send-input) - (define-key map "\e\C-x" 'eval-defun) ; for consistency with - (define-key map "\e\t" 'completion-at-point) ; lisp-interaction-mode - ;; These bindings are from `lisp-mode-shared-map' -- can you inherit - ;; from more than one keymap?? - (define-key map "\e\C-q" 'indent-sexp) - (define-key map "\177" 'backward-delete-char-untabify) - ;; Some convenience bindings for setting the working buffer - (define-key map "\C-c\C-b" 'ielm-change-working-buffer) - (define-key map "\C-c\C-f" 'ielm-display-working-buffer) - (define-key map "\C-c\C-v" 'ielm-print-working-buffer) - map) - "Keymap for IELM mode.") +(defvar-keymap ielm-map + :doc "Keymap for IELM mode." + "TAB" #'ielm-tab + "RET" #'ielm-return + "M-RET" #'ielm-return-for-effect + "C-j" #'ielm-send-input + "C-M-x" #'eval-defun ; for consistency with + "M-TAB" #'completion-at-point ; lisp-interaction-mode + ;; These bindings are from `lisp-mode-shared-map' -- can you inherit + ;; from more than one keymap?? + "C-M-q" #'indent-sexp + "DEL" #'backward-delete-char-untabify + ;; Some convenience bindings for setting the working buffer + "C-c C-b" #'ielm-change-working-buffer + "C-c C-f" #'ielm-display-working-buffer + "C-c C-v" #'ielm-print-working-buffer) (easy-menu-define ielm-menu ielm-map "IELM mode menu." From 57efc5d1bb60f6abb4766387b708e20532638135 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 13 Dec 2021 15:35:31 +0200 Subject: [PATCH 08/20] * src/sqlite.c (Fsqlite_open, Fsqlite_load_extension): Use ENCODE_FILE. --- src/sqlite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sqlite.c b/src/sqlite.c index 4968ce3f690..248ad478d57 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -247,7 +247,7 @@ If FILE is nil, an in-memory database will be opened instead. */) if (!NILP (file)) { CHECK_STRING (file); - file = encode_string (Fexpand_file_name (file, Qnil)); + file = ENCODE_FILE (Fexpand_file_name (file, Qnil)); name = xstrdup (SSDATA (file)); } else @@ -596,7 +596,7 @@ system-dependent file-name extension. */) { check_sqlite (db, false); CHECK_STRING (module); - Lisp_Object module_encoded = encode_string (Fexpand_file_name (module, Qnil)); + Lisp_Object module_encoded = ENCODE_FILE (Fexpand_file_name (module, Qnil)); sqlite3 *sdb = XSQLITE (db)->db; int result = sqlite3_load_extension (sdb, SSDATA (module_encoded), From 6170c5036e3802914723a288ef3191b58ef4a42d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 13 Dec 2021 15:51:38 +0200 Subject: [PATCH 09/20] Fix regression in help-mode prompt * lisp/help-macro.el (make-help-screen): Restore SPC and DEL in prompt. Reported by Colin Baxter . --- lisp/help-macro.el | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lisp/help-macro.el b/lisp/help-macro.el index 1fa9d82afd8..b3c7e2393a3 100644 --- a/lisp/help-macro.el +++ b/lisp/help-macro.el @@ -165,14 +165,18 @@ and then returns." (let ((cursor-in-echo-area t) (overriding-local-map local-map)) (setq key (read-key-sequence - (format "Type one of the options listed%s: " + (format "Type one of listed options%s: " (if (pos-visible-in-window-p (point-max)) "" (concat ", or " (help--key-description-fontified (kbd "")) - " or " + "/" (help--key-description-fontified (kbd "")) + "/" + (help--key-description-fontified (kbd "SPC")) + "/" + (help--key-description-fontified (kbd "DEL")) " to scroll")))) char (aref key 0))) From c952f8b059611739cd8f79151cc7ba7f71d7c95a Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 13 Dec 2021 09:29:42 -0500 Subject: [PATCH 10/20] lisp/pcomplete.el: Mark obsolete some unused functions * lisp/pcomplete.el (pcomplete-match-beginning, pcomplete-match-end): Mark as obsolete. (pcomplete-opt, pcomplete--here, pcomplete--help): Use lexical-binding. --- lisp/pcomplete.el | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el index 64acc416c23..1636e218821 100644 --- a/lisp/pcomplete.el +++ b/lisp/pcomplete.el @@ -680,8 +680,8 @@ user actually typed in." (match-string which arg) (throw 'pcompleted nil)))) -(defalias 'pcomplete-match-beginning 'match-beginning) -(defalias 'pcomplete-match-end 'match-end) +(define-obsolete-function-alias 'pcomplete-match-beginning #'match-beginning "29.1") +(define-obsolete-function-alias 'pcomplete-match-end #'match-end "29.1") (defsubst pcomplete--test (pred arg) "Perform a programmable completion predicate match." @@ -1006,7 +1006,7 @@ Arguments NO-GANGING and ARGS-FOLLOW are currently ignored." ((eq arg-char ?*) (pcomplete-executables)) ((eq arg-char ??) nil) ((eq arg-char ?.) (pcomplete-entries)) - ((eq arg-char ?\() (eval result)))))) + ((eq arg-char ?\() (eval result t)))))) (setq index (1+ index)))))))) (defun pcomplete--here (&optional form stub paring form-only) @@ -1040,7 +1040,7 @@ See the documentation for `pcomplete-here'." (funcall form) ;; Old calling convention, might still be used by files ;; byte-compiled with the older code. - (eval form))))) + (eval form t))))) (defmacro pcomplete-here* (&optional form stub form-only) @@ -1062,9 +1062,9 @@ See the documentation for `pcomplete-here'." pcomplete-window-restore-timer nil)) (define-obsolete-function-alias 'pcomplete-event-matches-key-specifier-p - 'eq "27.1") + #'eq "27.1") -(define-obsolete-function-alias 'pcomplete-read-event 'read-event "27.1") +(define-obsolete-function-alias 'pcomplete-read-event #'read-event "27.1") (defun pcomplete-show-completions (completions) "List in help buffer sorted COMPLETIONS. @@ -1244,7 +1244,7 @@ If specific documentation can't be given, be generic." (fboundp 'Info-goto-node)) (listp pcomplete-help))) (if (listp pcomplete-help) - (message "%s" (eval pcomplete-help)) + (message "%s" (eval pcomplete-help t)) (save-window-excursion (info)) (declare-function Info-goto-node "info" (nodename &optional fork strict-case)) From 0c24ccc9d8e8f9740040ce433635e8d67e77d7f0 Mon Sep 17 00:00:00 2001 From: Stefan Monnier Date: Mon, 13 Dec 2021 09:31:49 -0500 Subject: [PATCH 11/20] * lisp/emacs-lisp/generator.el (iter-yield): Simplify --- lisp/emacs-lisp/generator.el | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lisp/emacs-lisp/generator.el b/lisp/emacs-lisp/generator.el index cb0241017a0..ac1412704b0 100644 --- a/lisp/emacs-lisp/generator.el +++ b/lisp/emacs-lisp/generator.el @@ -143,8 +143,7 @@ the CPS state machinery." (setf ,static-var ,dynamic-var))))) (defmacro cps--with-dynamic-binding (dynamic-var static-var &rest body) - "Evaluate BODY such that generated atomic evaluations run with -DYNAMIC-VAR bound to STATIC-VAR." + "Run BODY's atomic evaluations run with DYNAMIC-VAR bound to STATIC-VAR." (declare (indent 2)) `(cps--with-value-wrapper (cps--make-dynamic-binding-wrapper ,dynamic-var ,static-var) @@ -645,12 +644,11 @@ modified copy." (iter-close iterator))))) iterator)))) -(defun iter-yield (value) +(defun iter-yield (_value) "When used inside a generator, yield control to caller. The caller of `iter-next' receives VALUE, and the next call to `iter-next' resumes execution with the form immediately following this `iter-yield' call." - (identity value) (error "`iter-yield' used outside a generator")) (defmacro iter-yield-from (value) From 7c4c72fa52aa80a5c399a4374ff1766377d1fd47 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Mon, 13 Dec 2021 15:57:04 +0100 Subject: [PATCH 12/20] Make two aliases obsolete in lisp/international/robin.el * lisp/international/robin.el (robin-transliterate-region) (robin-transliterate-buffer): Make obsolete. --- lisp/international/robin.el | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lisp/international/robin.el b/lisp/international/robin.el index c38cd822693..4c498d7f923 100644 --- a/lisp/international/robin.el +++ b/lisp/international/robin.el @@ -529,10 +529,10 @@ Use the longest match method to select a rule." (insert (cadr tree)) (delete-char (- end begin))))) -;; for backward compatibility - -(fset 'robin-transliterate-region 'robin-convert-region) -(fset 'robin-transliterate-buffer 'robin-convert-buffer) +(define-obsolete-function-alias 'robin-transliterate-region + #'robin-convert-region "29.1") +(define-obsolete-function-alias 'robin-transliterate-buffer + #'robin-convert-buffer "29.1") ;;; Reverse conversion From c1476afb99fbba316832c12e584a633684966c09 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Mon, 13 Dec 2021 15:57:54 +0100 Subject: [PATCH 13/20] Make alias obsolete in xscheme.el * lisp/progmodes/xscheme.el (xscheme-yank-previous-send): Make obsolete. --- lisp/progmodes/xscheme.el | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lisp/progmodes/xscheme.el b/lisp/progmodes/xscheme.el index 26ffe33b83e..e7667ebf51f 100644 --- a/lisp/progmodes/xscheme.el +++ b/lisp/progmodes/xscheme.el @@ -574,9 +574,8 @@ See also the commands \\[xscheme-yank-pop] and \\[xscheme-yank-push]." (if (consp arg) (exchange-point-and-mark))) -;; Old name, to avoid errors in users' init files. -(fset 'xscheme-yank-previous-send - 'xscheme-yank) +(define-obsolete-function-alias 'xscheme-yank-previous-send + #'xscheme-yank "29.1") (defun xscheme-yank-pop (arg) "Insert or replace a just-yanked expression with an older expression. From b30b33ed9b3cdacecebef73ad1131f03c635de7a Mon Sep 17 00:00:00 2001 From: Michael Albinus Date: Mon, 13 Dec 2021 16:09:56 +0100 Subject: [PATCH 14/20] ERT can generate JUnit test reports * .gitignore: Add test/**/*.xml. * admin/notes/emba: Mention JUnit test report. * etc/NEWS: ERT can generate JUnit test reports. * lisp/emacs-lisp/ert.el (xml-escape-string): Autoload. (ert-write-junit-test-report) (ert-write-junit-test-summary-report): New defuns. (ert-run-tests-batch, ert-summarize-tests-batch-and-exit): Call them. * test/Makefile.in (clean): Remove *.xml. * test/README: Mention $EMACS_TEST_JUNIT_REPORT environment variable. * test/infra/Makefile.in ($(FILE)): Generate header commentary. (clean): Remove. * test/infra/gitlab-ci.yml (variables): Set EMACS_TEST_JUNIT_REPORT. (.job-template): Use it in script and after_script. (.build-template, .gnustep-template, .filenotify-gio-template) (.native-comp-template): Adapt rules. (.test-template): Trigger JUnit test report. * test/infra/test-jobs.yml: Regenerate. --- .gitignore | 1 + admin/notes/emba | 4 ++ etc/NEWS | 7 ++ lisp/emacs-lisp/ert.el | 134 +++++++++++++++++++++++++++++++++++++-- test/Makefile.in | 1 + test/README | 3 + test/infra/Makefile.in | 6 +- test/infra/gitlab-ci.yml | 22 +++---- test/infra/test-jobs.yml | 1 + 9 files changed, 159 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index f1abb2ab687..7baee47b0a1 100644 --- a/.gitignore +++ b/.gitignore @@ -159,6 +159,7 @@ test/manual/etags/CTAGS test/manual/indent/*.new test/lisp/gnus/mml-sec-resources/random_seed test/lisp/play/fortune-resources/fortunes.dat +test/**/*.xml # ctags, etags. TAGS diff --git a/admin/notes/emba b/admin/notes/emba index f1b52b2cde0..2135c7a97cc 100644 --- a/admin/notes/emba +++ b/admin/notes/emba @@ -63,6 +63,10 @@ They can be downloaded from the server, visiting the URL , and selecting the job in question. +Every pipeline generates a JUnit test report for the respective test +jobs, which can be inspected on the pipeline web page. This test +report counts completed ERT tests, aborted tests are not counted. + * Emba configuration The emba configuration files are hosted on diff --git a/etc/NEWS b/etc/NEWS index b55b30665be..8d83b2a7e36 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -163,6 +163,12 @@ the previous definition to be discarded, which was probably not intended when this occurs in batch mode. To remedy the error, rename tests so that they all have unique names. ++++ +*** ERT can generate JUnit test reports. +When environment variable 'EMACS_TEST_JUNIT_REPORT' is set, ERT +generates a JUnit test report under this file name. This is useful +for Emacs integration into CI/CD test environments. + ** Emoji +++ @@ -1143,6 +1149,7 @@ This variable is bound to t during the preparation of a "*Help*" buffer. ** 'date-to-time' now assumes earliest values if its argument lacks month, day, or time. For example, (date-to-time "2021-12-04") now assumes a time of 00:00 instead of signaling an error. + * Changes in Emacs 29.1 on Non-Free Operating Systems diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el index 946193e40dc..981e23931c2 100644 --- a/lisp/emacs-lisp/ert.el +++ b/lisp/emacs-lisp/ert.el @@ -65,6 +65,8 @@ (require 'pp) (require 'map) +(autoload 'xml-escape-string "xml.el") + ;;; UI customization options. (defgroup ert () @@ -247,7 +249,6 @@ in batch mode, an error is signalled. "%s\\(\\s-\\|$\\)") "The regexp the `find-function' mechanisms use for finding test definitions.") - (define-error 'ert-test-failed "Test failed") (define-error 'ert-test-skipped "Test skipped") @@ -677,7 +678,6 @@ and is displayed in front of the value of MESSAGE-FORM." ,@body)) - ;;; Facilities for running a single test. (defvar ert-debug-on-error nil @@ -1437,7 +1437,9 @@ Returns the stats object." (if (getenv "EMACS_TEST_VERBOSE") (ert-reason-for-test-result result) "")))) - (message "%s" ""))))) + (message "%s" "")) + (when (getenv "EMACS_TEST_JUNIT_REPORT") + (ert-write-junit-test-report stats))))) (test-started) (test-ended (cl-destructuring-bind (stats test result) event-args @@ -1525,6 +1527,128 @@ the tests)." (backtrace)) (kill-emacs 2)))) +(defun ert-write-junit-test-report (stats) + "Write a JUnit test report, generated from STATS." + ;; https://www.ibm.com/docs/de/developer-for-zos/14.1.0?topic=formats-junit-xml-format + ;; https://llg.cubic.org/docs/junit/ + (unless (zerop (length (ert--stats-tests stats))) + (when-let ((test-file + (symbol-file + (ert-test-name (aref (ert--stats-tests stats) 0)) 'ert--test))) + (with-temp-file (file-name-with-extension test-file "xml") + (insert "\n") + (insert (format "\n" + (file-name-nondirectory test-file) + (ert-stats-total stats) + (ert-stats-completed-unexpected stats) + (ert-stats-skipped stats) + (float-time + (time-subtract + (ert--stats-end-time stats) + (ert--stats-start-time stats))))) + (insert (format " \n" + (file-name-nondirectory test-file) + (ert-stats-total stats) + (ert-stats-completed-unexpected stats) + (ert-stats-skipped stats) + (float-time + (time-subtract + (ert--stats-end-time stats) + (ert--stats-start-time stats))) + (ert--format-time-iso8601 (ert--stats-end-time stats)))) + (insert " \n" + (format " \n" + (ert--stats-selector stats)) + " \n") + (cl-loop for test across (ert--stats-tests stats) + for result = (ert-test-most-recent-result test) do + (insert (format " \n") + (insert ">\n") + (if (ert-test-skipped-p result) + (insert (format " \n" + (xml-escape-string + (string-trim + (ert-reason-for-test-result result))) + (ert-string-for-test-result + result + (ert-test-result-expected-p + test result))) + (xml-escape-string + (string-trim + (ert-reason-for-test-result result))) + "\n" + " \n") + (unless + (ert-test-result-type-p + result (ert-test-expected-result-type test)) + (insert (format " \n" + (xml-escape-string + (string-trim + (ert-reason-for-test-result result))) + (ert-string-for-test-result + result + (ert-test-result-expected-p + test result))) + (xml-escape-string + (string-trim + (ert-reason-for-test-result result))) + "\n" + " \n"))) + (unless (zerop (length (ert-test-result-messages result))) + (insert " \n" + (xml-escape-string + (ert-test-result-messages result)) + " \n")) + (insert " \n"))) + (insert " \n") + (insert "\n"))))) + +(defun ert-write-junit-test-summary-report (&rest logfiles) + "Write a JUnit summary test report, generated from LOGFILES." + (let ((report (file-name-with-extension + (getenv "EMACS_TEST_JUNIT_REPORT") "xml")) + (tests 0) (failures 0) (skipped 0) (time 0) (id 0)) + (with-temp-file report + (dolist (logfile logfiles) + (let ((test-file (file-name-with-extension logfile "xml"))) + (when (file-readable-p test-file) + (insert-file-contents-literally test-file) + (when (looking-at-p + (regexp-quote "")) + (delete-region (point) (line-beginning-position 2))) + (when (looking-at + "") + (cl-incf tests (string-to-number (match-string 1))) + (cl-incf failures (string-to-number (match-string 2))) + (cl-incf skipped (string-to-number (match-string 3))) + (cl-incf time (string-to-number (match-string 4))) + (delete-region (point) (line-beginning-position 2))) + (when (looking-at " ") + (delete-region (point) (line-beginning-position 2))) + (narrow-to-region (point-max) (point-max))))) + + (insert "\n") + (widen) + (goto-char (point-min)) + (insert "\n") + (insert (format "\n" + (file-name-nondirectory report) + tests failures skipped time))))) (defun ert-summarize-tests-batch-and-exit (&optional high) "Summarize the results of testing. @@ -1540,6 +1664,8 @@ If HIGH is a natural number, the HIGH long lasting tests are summarized." ;; behavior. (setq attempt-stack-overflow-recovery nil attempt-orderly-shutdown-on-fatal-signal nil) + (when (getenv "EMACS_TEST_JUNIT_REPORT") + (apply #'ert-write-junit-test-summary-report command-line-args-left)) (let ((nlogs (length command-line-args-left)) (ntests 0) (nrun 0) (nexpected 0) (nunexpected 0) (nskipped 0) nnotrun logfile notests badtests unexpected skipped tests) @@ -1855,7 +1981,6 @@ Also sets `ert--results-progress-bar-button-begin'." ;; should test it again.) "\n"))) - (defvar ert-test-run-redisplay-interval-secs .1 "How many seconds ERT should wait between redisplays while running tests. @@ -2037,7 +2162,6 @@ STATS is the stats object; LISTENER is the results listener." (goto-char (1- (point-max))) buffer))))) - (defvar ert--selector-history nil "List of recent test selectors read from terminal.") diff --git a/test/Makefile.in b/test/Makefile.in index f2c49584e7f..eeda2918fa3 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -353,6 +353,7 @@ mostlyclean: clean: find . '(' -name '*.log' -o -name '*.log~' ')' $(FIND_DELETE) + find . '(' -name '*.xml' -a ! -path '*resources*' ')' $(FIND_DELETE) rm -f ${srcdir}/lisp/gnus/mml-sec-resources/random_seed rm -f $(test_module_dir)/*.o $(test_module_dir)/*.so \ $(test_module_dir)/*.dll diff --git a/test/README b/test/README index 4d447c9bf15..2bd84b5f9b3 100644 --- a/test/README +++ b/test/README @@ -114,6 +114,9 @@ mode--only the names of the failed tests are listed. If the $EMACS_TEST_VERBOSE environment variable is set, the failure summaries will also include the data from the failing test. +If the $EMACS_TEST_JUNIT_REPORT environment variable is set to a file +name, a JUnit test report is generated under this name. + Some of the tests require a remote temporary directory (autorevert-tests.el, filenotify-tests.el, shadowfile-tests.el and tramp-tests.el). Per default, a mock-up connection method is used diff --git a/test/infra/Makefile.in b/test/infra/Makefile.in index fd11d367983..e4f99743e09 100644 --- a/test/infra/Makefile.in +++ b/test/infra/Makefile.in @@ -93,10 +93,8 @@ all: generate-test-jobs .PHONY: generate-test-jobs $(FILE) $(SUBDIR_TARGETS) -generate-test-jobs: clean $(FILE) $(SUBDIR_TARGETS) +generate-test-jobs: $(FILE) $(SUBDIR_TARGETS) $(FILE): $(AM_V_GEN) - -clean: - @rm -f $(FILE) + @echo "# Generated by \"make generate-test-jobs\", don't edit." >$(FILE) diff --git a/test/infra/gitlab-ci.yml b/test/infra/gitlab-ci.yml index b0ea6813b30..3903642c792 100644 --- a/test/infra/gitlab-ci.yml +++ b/test/infra/gitlab-ci.yml @@ -44,6 +44,7 @@ workflow: variables: GIT_STRATEGY: fetch EMACS_EMBA_CI: 1 + EMACS_TEST_JUNIT_REPORT: junit-test-report.xml EMACS_TEST_TIMEOUT: 3600 EMACS_TEST_VERBOSE: 1 # Use TLS https://docs.gitlab.com/ee/ci/docker/using_docker_build.html#tls-enabled @@ -85,7 +86,7 @@ default: # TODO: with make -j4 several of the tests were failing, for # example shadowfile-tests, but passed without it. - 'export PWD=$(pwd)' - - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} -e EMACS_TEST_TIMEOUT=${EMACS_TEST_TIMEOUT} -e EMACS_TEST_VERBOSE=${EMACS_TEST_VERBOSE} --volumes-from $(docker ps -q -f "label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name ${test_name} ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git fetch ${PWD} HEAD && echo checking out these updated files && git diff --name-only FETCH_HEAD && ( git diff --name-only FETCH_HEAD | xargs git checkout -f FETCH_HEAD ) && make -j4 && make ${make_params}"' + - 'docker run -i -e EMACS_EMBA_CI=${EMACS_EMBA_CI} -e EMACS_TEST_JUNIT_REPORT=${EMACS_TEST_JUNIT_REPORT} -e EMACS_TEST_TIMEOUT=${EMACS_TEST_TIMEOUT} -e EMACS_TEST_VERBOSE=${EMACS_TEST_VERBOSE} --volumes-from $(docker ps -q -f "label=com.gitlab.gitlab-runner.job.id=${CI_JOB_ID}"):ro --name ${test_name} ${CI_REGISTRY_IMAGE}:${target}-${BUILD_TAG} /bin/bash -c "git fetch ${PWD} HEAD && echo checking out these updated files && git diff --name-only FETCH_HEAD && ( git diff --name-only FETCH_HEAD | xargs git checkout -f FETCH_HEAD ) && make -j4 && make ${make_params}"' after_script: # - docker ps -a # - printenv @@ -93,7 +94,8 @@ default: # Prepare test artifacts. - test -n "$(docker ps -aq -f name=${test_name})" && docker cp ${test_name}:checkout/test ${test_name} - test -n "$(docker ps -aq -f name=${test_name})" && docker rm ${test_name} - - find ${test_name} ! -name "*.log" -type f -delete + - find ${test_name} ! \( -name "*.log" -o -name ${EMACS_TEST_JUNIT_REPORT} \) -type f -delete + # BusyBox find does not know -empty. - find ${test_name} -type d -depth -exec rmdir {} + 2>/dev/null .build-template: @@ -103,7 +105,6 @@ default: when: always - changes: - "**.in" - - "**.yml" - GNUmakefile - aclocal.m4 - autogen.sh @@ -112,7 +113,7 @@ default: - lib/malloc/*.{h,c} - lisp/emacs-lisp/*.el - src/*.{h,c} - - test/infra/Dockerfile.emba + - test/infra/* - changes: # gfilemonitor, kqueue - src/gfilenotify.c @@ -133,9 +134,11 @@ default: name: ${test_name} public: true expire_in: 1 week + when: always paths: - ${test_name}/ - when: always + reports: + junit: ${test_name}/${EMACS_TEST_JUNIT_REPORT} .gnustep-template: rules: @@ -143,12 +146,11 @@ default: - if: '$CI_PIPELINE_SOURCE == "schedule"' changes: - "**.in" - - "**.yml" - src/ns*.{h,m} - src/macfont.{h,m} - lisp/term/ns-win.el - nextstep/** - - test/infra/Dockerfile.emba + - test/infra/* .filenotify-gio-template: rules: @@ -156,12 +158,11 @@ default: - if: '$CI_PIPELINE_SOURCE == "schedule"' changes: - "**.in" - - "**.yml" - lisp/autorevert.el - lisp/filenotify.el - lisp/net/tramp-sh.el - src/gfilenotify.c - - test/infra/Dockerfile.emba + - test/infra/* - test/lisp/autorevert-tests.el - test/lisp/filenotify-tests.el @@ -171,11 +172,10 @@ default: - if: '$CI_PIPELINE_SOURCE == "schedule"' changes: - "**.in" - - "**.yml" - lisp/emacs-lisp/comp.el - lisp/emacs-lisp/comp-cstr.el - src/comp.{h,m} - - test/infra/Dockerfile.emba + - test/infra/* - test/src/comp-resources/*.el - test/src/comp-tests.el timeout: 8 hours diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml index bad8575b5c5..63b052bf8c7 100644 --- a/test/infra/test-jobs.yml +++ b/test/infra/test-jobs.yml @@ -1,3 +1,4 @@ +# Generated by "make generate-test-jobs", don't edit. test-lib-src-inotify: stage: normal From ae169bda2cbec49e30a7ca15828c45f2c638e500 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Mon, 13 Dec 2021 18:28:13 +0100 Subject: [PATCH 15/20] ; Add a FIXME regarding the GMP memory allocation functions. * src/bignum.c (init_bignum): Add a warning about the technically incorrect use of the GMP memory allocation functions. --- src/bignum.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bignum.c b/src/bignum.c index 1ac75c19e24..5c587fc6dba 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -53,6 +53,15 @@ init_bignum (void) { eassert (mp_bits_per_limb == GMP_NUMB_BITS); integer_width = 1 << 16; + + /* FIXME: The Info node `(gmp) Custom Allocation' states: "No error + return is allowed from any of these functions, if they return + then they must have performed the specified operation. [...] + There's currently no defined way for the allocation functions to + recover from an error such as out of memory, they must terminate + program execution. A 'longjmp' or throwing a C++ exception will + have undefined results." But xmalloc and xrealloc do call + 'longjmp'. */ mp_set_memory_functions (xmalloc, xrealloc_for_gmp, xfree_for_gmp); for (int i = 0; i < ARRAYELTS (mpz); i++) From cea8deea7288efd15880dc035dccfb8d9866dff8 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Mon, 13 Dec 2021 21:02:38 +0200 Subject: [PATCH 16/20] ; * src/xdisp.c (move_it_vertically_backward): Clarify commentary. --- src/xdisp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/xdisp.c b/src/xdisp.c index 5d687e1c291..597b12d4d68 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -10233,11 +10233,12 @@ move_it_to (struct it *it, ptrdiff_t to_charpos, int to_x, int to_y, int to_vpos /* Move iterator IT backward by a specified y-distance DY, DY >= 0. - If DY > 0, move IT backward at least that many pixels. DY = 0 - means move IT backward to the preceding line start or BEGV. This - function may move over more than DY pixels if IT->current_y - DY - ends up in the middle of a line; in this case IT->current_y will be - set to the top of the line moved to. */ + If DY > 0, move IT backward that many pixels. + DY = 0 means move IT backward to the preceding line start or to BEGV. + This function may move over less or more than DY pixels if + IT->current_y - DY ends up in the middle of a line; in this case + IT->current_y will be set to the top of the line either before or + after the exact pixel coordinate. */ void move_it_vertically_backward (struct it *it, int dy) From 855f1bd17667781761e62ed439ecc99fe972cf1a Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Tue, 14 Dec 2021 02:16:41 +0100 Subject: [PATCH 17/20] completion.el: Make two compat aliases obsolete * lisp/completion.el (cmpl-syntax-table, initialize-completions): Make compat aliases obsolete. --- lisp/completion.el | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lisp/completion.el b/lisp/completion.el index 643f2da0d21..a77cccde643 100644 --- a/lisp/completion.el +++ b/lisp/completion.el @@ -492,7 +492,7 @@ Used to decide whether to save completions.") table)) ;; Old name, non-namespace-clean. -(defvaralias 'cmpl-syntax-table 'completion-syntax-table) +(define-obsolete-variable-alias 'cmpl-syntax-table 'completion-syntax-table "29.1") (defvar-local completion-syntax-table completion-standard-syntax-table "This variable holds the current completion syntax table.") @@ -2220,7 +2220,7 @@ TYPE is the type of the wrapper to be added. Can be :before or :under." (completion-def-wrapper 'delete-backward-char-untabify :backward) ;; Old name, non-namespace-clean. -(defalias 'initialize-completions #'completion-initialize) +(define-obsolete-function-alias 'initialize-completions #'completion-initialize "29.1") (provide 'completion) From 9de8eec3bc9be2f6e7debf26159c1761c47df909 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Tue, 14 Dec 2021 03:08:37 +0100 Subject: [PATCH 18/20] * make-dist: Don't run "make --question info". (Bug#52322) --- make-dist | 7 ------- 1 file changed, 7 deletions(-) diff --git a/make-dist b/make-dist index b069130ca61..db7a74b82b3 100755 --- a/make-dist +++ b/make-dist @@ -299,13 +299,6 @@ if [ $check = yes ]; then echo "${bogosities}" fi - ## This exits with non-zero status if any .info files need - ## rebuilding. - if [ -r Makefile ] && [ "$with_info" = "yes" ]; then - echo "Checking to see if info files are up-to-date..." - make --question info || error=yes - fi - ## Is this a release? case $version in [1-9][0-9].[0-9]) From 3607508f3ffa3c32bc913a8be08f3d00bcde8027 Mon Sep 17 00:00:00 2001 From: Stefan Kangas Date: Tue, 14 Dec 2021 03:38:11 +0100 Subject: [PATCH 19/20] Set calc-make-windows-dedicated to nil by default * lisp/calc/calc.el (calc-make-windows-dedicated): Default to nil. (Bug#52016) --- etc/NEWS | 6 +++--- lisp/calc/calc.el | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index eb65213ac2f..d2565e50e1e 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1588,9 +1588,9 @@ and the result is not truncated in any way. It no longer has lower precedence than '+' and '-'. --- -*** Calc now marks its windows dedicated. -The new user option 'calc-make-windows-dedicated' controls this. It -is t by default; set to nil to get back the old behavior. +*** New user option 'calc-make-windows-dedicated'. +When this user option is non-nil, Calc will mark its windows as +dedicated. ** Calendar diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el index 553bdc9c6ed..e97315165b3 100644 --- a/lisp/calc/calc.el +++ b/lisp/calc/calc.el @@ -1423,7 +1423,7 @@ commands given here will actually operate on the *Calculator* stack." (require 'calc-ext) (calc-set-language calc-language calc-language-option t))) -(defcustom calc-make-windows-dedicated t +(defcustom calc-make-windows-dedicated nil "If non-nil, windows displaying Calc buffers will be marked dedicated. See `window-dedicated-p' for what that means." :version "28.1" From 8c0f9be0d1ace6437d4c604b9af79b7b0006dec4 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Tue, 14 Dec 2021 09:29:06 +0100 Subject: [PATCH 20/20] Only allow SQLite extensions from an allowlist * src/sqlite.c (Fsqlite_load_extension): Only allow extensions from an allowlist. --- src/sqlite.c | 36 +++++++++++++++++++++++++++++++----- test/src/sqlite-tests.el | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/sqlite.c b/src/sqlite.c index 248ad478d57..428b84b21e7 100644 --- a/src/sqlite.c +++ b/src/sqlite.c @@ -591,16 +591,42 @@ DEFUN ("sqlite-load-extension", Fsqlite_load_extension, doc: /* Load an SQlite MODULE into DB. MODULE should be the name of an SQlite module's file, a shared library in the system-dependent format and having a -system-dependent file-name extension. */) +system-dependent file-name extension. + +Only modules on Emacs' list of allowed modules can be loaded. */) (Lisp_Object db, Lisp_Object module) { check_sqlite (db, false); CHECK_STRING (module); - Lisp_Object module_encoded = ENCODE_FILE (Fexpand_file_name (module, Qnil)); - sqlite3 *sdb = XSQLITE (db)->db; - int result = sqlite3_load_extension (sdb, SSDATA (module_encoded), - NULL, NULL); + /* Add names of useful and free modules here. */ + const char *allowlist[3] = { "pcre", "csvtable", NULL }; + char *name = SSDATA (Ffile_name_nondirectory (module)); + /* Possibly skip past a common prefix. */ + const char *prefix = "libsqlite3_mod_"; + if (!strncmp (name, prefix, strlen (prefix))) + name += strlen (prefix); + + bool do_allow = false; + for (const char **allow = allowlist; *allow; allow++) + { + if (strlen (*allow) < strlen (name) + && !strncmp (*allow, name, strlen (*allow)) + && (!strcmp (name + strlen (*allow), ".so") + || !strcmp (name + strlen (*allow), ".DLL"))) + { + do_allow = true; + break; + } + } + + if (!do_allow) + xsignal (Qerror, build_string ("Module name not on allowlist")); + + int result = sqlite3_load_extension + (XSQLITE (db)->db, + SSDATA (ENCODE_FILE (Fexpand_file_name (module, Qnil))), + NULL, NULL); if (result == SQLITE_OK) return Qt; return Qnil; diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 6a88f0fd6ca..d1076e481c4 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -182,4 +182,36 @@ (sqlite-close db) (should-error (sqlite-select db "select * from test6")))) +(ert-deftest sqlite-load-extension () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/notpcre.so")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/n")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3")) + (should + (memq + (sqlite-load-extension db "/usr/lib/sqlite3/pcre.so") + '(nil t))) + + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_notcsvtable.so")) + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtablen.so")) + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable")) + (should + (memq + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable.so") + '(nil t))))) + ;;; sqlite-tests.el ends here