From f91bf9df892417a2e4add6d0d77ac5123a579bfc Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Wed, 1 Feb 2023 14:13:54 +0200 Subject: [PATCH 01/23] Unbreak the MS-Windows build * src/treesit.c (ts_query_pattern_count) [WINDOWSNT]: Load from the library and define as macro. --- src/treesit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/treesit.c b/src/treesit.c index b163685419f..405aec1f47e 100644 --- a/src/treesit.c +++ b/src/treesit.c @@ -72,6 +72,7 @@ along with GNU Emacs. If not, see . */ #undef ts_query_cursor_set_byte_range #undef ts_query_delete #undef ts_query_new +#undef ts_query_pattern_count #undef ts_query_predicates_for_pattern #undef ts_query_string_value_for_id #undef ts_set_allocator @@ -135,6 +136,7 @@ DEF_DLL_FN (void, ts_query_cursor_set_byte_range, DEF_DLL_FN (void, ts_query_delete, (TSQuery *)); DEF_DLL_FN (TSQuery *, ts_query_new, (const TSLanguage *, const char *, uint32_t, uint32_t *, TSQueryError *)); +DEF_DLL_FN (uint32_t, ts_query_pattern_count, (const TSQuery *)); DEF_DLL_FN (const TSQueryPredicateStep *, ts_query_predicates_for_pattern, ( const TSQuery *, uint32_t, uint32_t *)); DEF_DLL_FN (const char *, ts_query_string_value_for_id, @@ -200,6 +202,7 @@ init_treesit_functions (void) LOAD_DLL_FN (library, ts_query_cursor_set_byte_range); LOAD_DLL_FN (library, ts_query_delete); LOAD_DLL_FN (library, ts_query_new); + LOAD_DLL_FN (library, ts_query_pattern_count); LOAD_DLL_FN (library, ts_query_predicates_for_pattern); LOAD_DLL_FN (library, ts_query_string_value_for_id); LOAD_DLL_FN (library, ts_set_allocator); @@ -256,6 +259,7 @@ init_treesit_functions (void) #define ts_query_cursor_set_byte_range fn_ts_query_cursor_set_byte_range #define ts_query_delete fn_ts_query_delete #define ts_query_new fn_ts_query_new +#define ts_query_pattern_count fn_ts_query_pattern_count #define ts_query_predicates_for_pattern fn_ts_query_predicates_for_pattern #define ts_query_string_value_for_id fn_ts_query_string_value_for_id #define ts_set_allocator fn_ts_set_allocator From ea1bb263153d406479e782872820af4f9926ac7d Mon Sep 17 00:00:00 2001 From: Juri Linkov Date: Wed, 1 Feb 2023 20:05:52 +0200 Subject: [PATCH 02/23] * doc/emacs/basic.texi (Repeating): Mention describe-repeat-maps (bug#61183). * lisp/repeat.el (describe-repeat-maps): Add more explanation to the docstring. Suggested by Robert Pluim . --- doc/emacs/basic.texi | 17 +++++++++-------- lisp/repeat.el | 3 ++- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index 2cc45a8805e..d8a354ff42d 100644 --- a/doc/emacs/basic.texi +++ b/doc/emacs/basic.texi @@ -887,6 +887,7 @@ z z z}. The first @kbd{C-x z} repeats the command once, and each subsequent @kbd{z} repeats it once again. @findex repeat-mode +@findex describe-repeat-maps @vindex repeat-exit-key @vindex repeat-exit-timeout Also you can activate @code{repeat-mode} that temporarily enables a @@ -895,11 +896,11 @@ Currently supported shorter key sequences are @kbd{C-x u u} instead of @kbd{C-x u C-x u} to undo many changes, @kbd{C-x o o} instead of @kbd{C-x o C-x o} to switch several windows, @kbd{C-x @{ @{ @} @} ^ ^ v v} to resize the selected window interactively, @kbd{M-g n n p p} to -navigate @code{next-error} matches, and @kbd{C-x ] ] [ [} to navigate -through pages. Any other key exits transient mode and then is -executed normally. The user option @code{repeat-exit-key} defines an -additional key to exit this transient mode. Also it's possible to -break the repetition chain automatically after some idle time by -customizing the user option @code{repeat-exit-timeout} to specify the -idle time in seconds after which this transient mode will be turned -off. +navigate @code{next-error} matches, @kbd{C-x ] ] [ [} to navigate +through pages, and other keys listed by @code{describe-repeat-maps}. +Any other key exits transient mode and then is executed normally. The +user option @code{repeat-exit-key} defines an additional key to exit +this transient mode. Also it's possible to break the repetition chain +automatically after some idle time by customizing the user option +@code{repeat-exit-timeout} to specify the idle time in seconds after +which this transient mode will be turned off. diff --git a/lisp/repeat.el b/lisp/repeat.el index 0124ff4bc0c..ce59b310792 100644 --- a/lisp/repeat.el +++ b/lisp/repeat.el @@ -597,7 +597,8 @@ This function can be used to force exit of repetition while it's active." (defun describe-repeat-maps () "Describe mappings of commands repeatable by symbol property `repeat-map'. -Used in `repeat-mode'." +If `repeat-mode' is enabled, these keymaps determine which single key +can be used to repeat a command invoked via a full key sequence." (interactive) (require 'help-fns) (let ((help-buffer-under-preparation t)) From 9715715ac163fc0b3ce6e170eb9c74b5f4ad8267 Mon Sep 17 00:00:00 2001 From: Nicolas Martyanoff Date: Wed, 1 Feb 2023 22:17:57 -0500 Subject: [PATCH 03/23] (eshell--complete-commands-list): Fix regression in fix to bug#48995 Copyright-Paperwork-Exempt: Yes * lisp/eshell/em-cmpl.el (eshell--complete-commands-list): Fix misuse of `completion-table-dynamic` when completing a file name. --- lisp/eshell/em-cmpl.el | 43 +++++++++++++----------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el index ca51cee2558..4f656b16a8e 100644 --- a/lisp/eshell/em-cmpl.el +++ b/lisp/eshell/em-cmpl.el @@ -378,31 +378,6 @@ to writing a completion function." args) posns))) -(defun eshell--pcomplete-executables () - "Complete amongst a list of directories and executables. - -Wrapper for `pcomplete-executables' or `pcomplete-dirs-or-entries', -depending on the value of `eshell-force-execution'. - -Adds path prefix to candidates independent of `action' value." - ;; `pcomplete-entries' returns filenames without path on `action' to - ;; use current string directory as done in `completion-file-name-table' - ;; when `action' is nil to construct executable candidates. - (let ((table (if eshell-force-execution - (pcomplete-dirs-or-entries nil #'file-readable-p) - (pcomplete-executables)))) - (lambda (string pred action) - (let ((cands (funcall table string pred action))) - (if (eq action t) - (let ((specdir (file-name-directory string))) - (mapcar - (lambda (cand) - (if (stringp cand) - (file-name-concat specdir cand) - cand)) - cands)) - cands))))) - (defun eshell--complete-commands-list () "Generate list of applicable, visible commands." ;; Building the commands list can take quite a while, especially over Tramp @@ -413,11 +388,19 @@ Adds path prefix to candidates independent of `action' value." ;; we complete. Adjust `pcomplete-stub' accordingly! (if (and (> (length pcomplete-stub) 0) (eq (aref pcomplete-stub 0) eshell-explicit-command-char)) - (setq pcomplete-stub (substring pcomplete-stub 1))))) - (completion-table-dynamic - (lambda (filename) - (if (file-name-directory filename) - (eshell--pcomplete-executables) + (setq pcomplete-stub (substring pcomplete-stub 1)))) + (filename (pcomplete-arg))) + ;; Do not use `completion-table-dynamic' when completing a command file + ;; name since it doesn't know about boundaries and would end up doing silly + ;; things like adding a SPC char when completing to "/usr/sbin/". + ;; + ;; If you work on this function, be careful not to reintroduce bug#48995. + (if (file-name-directory filename) + (if eshell-force-execution + (pcomplete-dirs-or-entries nil #'file-readable-p) + (pcomplete-executables)) + (completion-table-dynamic + (lambda (filename) (let* ((paths (eshell-get-path)) (cwd (file-name-as-directory (expand-file-name default-directory))) From be304bb3286eb27e1aa8248eb3904925ed73dfcb Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 2 Feb 2023 12:35:16 +0200 Subject: [PATCH 04/23] ; * etc/NEWS: Mention the 'utf-8-auto' bugfix (bug#60750). --- etc/NEWS | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/etc/NEWS b/etc/NEWS index fb211f9b7d0..d402cc82c4a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -563,6 +563,20 @@ The variable 'font-lock-support-mode' is occasionally useful for debugging purposes. It is now a regular variable (instead of a user option) and can be set to nil to disable Just-in-time Lock mode. ++++ +** The 'utf-8-auto' coding-system now produces BOM on encoding. +This is actually a bugfix, since this is how 'utf-8-auto' was +documented from day one; it just didn't behave according to +documentation. It turns out some Lisp programs were using this +coding-system on the wrong assumption that the "auto" part means some +automagic handling of the end-of-line (EOL) format conversion; those +program will now start to fail, because BOM signature in UTF-8 encoded +text is rarely expected. That is the reason we mention this bugfix +here. + +In general, this coding-system should probably never be used for +encoding, only for decoding. + * Changes in Emacs 29.1 From c6660a6d6de9450f030db6d77eeaa76b8bdd14ef Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 2 Feb 2023 15:34:58 +0200 Subject: [PATCH 05/23] Improve documentation of 'repeat-mode' and related variables * lisp/bindings.el (next-error-repeat-map) (page-navigation-repeat-map, undo-repeat-map): * lisp/tab-bar.el (tab-bar-switch-repeat-map) (tab-bar-move-repeat-map): * lisp/window.el (other-window-repeat-map) (resize-window-repeat-map): Mention repeatable commands in the doc strings. * lisp/repeat.el (repeat-exit-timeout, repeat-check-key) (repeat-echo-function, repeat-mode, repeat-check-key) (repeat-check-map, repeat-echo-message-string) (repeat-echo-message, repeat-echo-mode-line) (describe-repeat-maps): Improve wording of doc strings. (describe-repeat-maps): Improve wording of the heading line. (Bug#61183) * doc/emacs/basic.texi (Repeating): Clarify and improve wording of 'repeat-mode' documentation. --- doc/emacs/basic.texi | 46 +++++++++++++++++++++++++++++------------ lisp/bindings.el | 6 +++--- lisp/repeat.el | 49 +++++++++++++++++++++++++++----------------- lisp/tab-bar.el | 4 ++-- lisp/window.el | 5 +++-- 5 files changed, 71 insertions(+), 39 deletions(-) diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi index d8a354ff42d..a271cb65bdc 100644 --- a/doc/emacs/basic.texi +++ b/doc/emacs/basic.texi @@ -890,17 +890,37 @@ subsequent @kbd{z} repeats it once again. @findex describe-repeat-maps @vindex repeat-exit-key @vindex repeat-exit-timeout - Also you can activate @code{repeat-mode} that temporarily enables a -transient mode with short keys after a limited number of commands. -Currently supported shorter key sequences are @kbd{C-x u u} instead of -@kbd{C-x u C-x u} to undo many changes, @kbd{C-x o o} instead of -@kbd{C-x o C-x o} to switch several windows, @kbd{C-x @{ @{ @} @} ^ ^ -v v} to resize the selected window interactively, @kbd{M-g n n p p} to -navigate @code{next-error} matches, @kbd{C-x ] ] [ [} to navigate -through pages, and other keys listed by @code{describe-repeat-maps}. -Any other key exits transient mode and then is executed normally. The -user option @code{repeat-exit-key} defines an additional key to exit -this transient mode. Also it's possible to break the repetition chain -automatically after some idle time by customizing the user option + You can also activate @code{repeat-mode} which allows repeating +commands bound to sequences of two or more keys by typing a single +character. For example, after typing @w{@kbd{C-x u}} (@code{undo}, +@pxref{Undo}) to undo the most recent edits, you can undo many more +edits by typing @w{@kbd{u u u@dots{}}}. Similarly, type @w{@kbd{C-x o +o o@dots{}}} instead of @w{@kbd{C-x o C-x o C-x o@dots{}}} to switch +to the window several windows away. This works by entering a +transient repeating mode after you type the full key sequence that +invokes the command; the single-key shortcuts are shown in the echo +area. + +Only some commands support repetition in @code{repeat-mode}; type +@w{@kbd{M-x describe-repeat-maps @key{RET}}} to see which ones. + +The single-character shortcuts enabled by the transient repeating mode +do not need to be identical: for example, after typing @w{@kbd{C-x +@{}}, either @kbd{@{} or @kbd{@}} or @kbd{^} or @kbd{v}, or any series +that mixes these characters in any order, will resize the selected +window in respective ways. Similarly, after @w{@kbd{M-g n}} or +@kbd{M-g p}, typing any sequence of @kbd{n} and/or @kbd{p} in any mix +will repeat @code{next-error} and @code{previous-error} to navigate in +a @file{*compilation*} or @file{*grep*} buffer (@pxref{Compilation +Mode}). + +Typing any key other than those defined to repeat the previous command +exits the transient repeating mode, and then the key you typed is +executed normally. You can also define a key which will exit the +transient repeating mode @emph{without} executing the key which caused +the exit. To this end, customize the user option +@code{repeat-exit-key} to name a key; one natural value is @key{RET}. +Finally, it's possible to break the repetition chain automatically +after some amount of idle time: customize the user option @code{repeat-exit-timeout} to specify the idle time in seconds after -which this transient mode will be turned off. +which this transient repetition mode will be turned off automatically. diff --git a/lisp/bindings.el b/lisp/bindings.el index 34aa8399a96..f4881ac388c 100644 --- a/lisp/bindings.el +++ b/lisp/bindings.el @@ -1009,7 +1009,7 @@ if `inhibit-field-text-motion' is non-nil." ;; no idea whereas to bind it. Any suggestion welcome. -stef ;; (define-key ctl-x-map "U" 'undo-only) (defvar-keymap undo-repeat-map - :doc "Keymap to repeat undo key sequences \\`C-x u u'. Used in `repeat-mode'." + :doc "Keymap to repeat `undo' commands. Used in `repeat-mode'." :repeat t "u" #'undo) @@ -1106,7 +1106,7 @@ if `inhibit-field-text-motion' is non-nil." (define-key ctl-x-map "`" 'next-error) (defvar-keymap next-error-repeat-map - :doc "Keymap to repeat `next-error' key sequences. Used in `repeat-mode'." + :doc "Keymap to repeat `next-error' and `previous-error'. Used in `repeat-mode'." :repeat t "n" #'next-error "M-n" #'next-error @@ -1468,7 +1468,7 @@ if `inhibit-field-text-motion' is non-nil." (define-key ctl-x-map "]" 'forward-page) (defvar-keymap page-navigation-repeat-map - :doc "Keymap to repeat page navigation key sequences. Used in `repeat-mode'." + :doc "Keymap to repeat `forward-page' and `backward-page'. Used in `repeat-mode'." :repeat t "]" #'forward-page "[" #'backward-page) diff --git a/lisp/repeat.el b/lisp/repeat.el index ce59b310792..37d4aaec985 100644 --- a/lisp/repeat.el +++ b/lisp/repeat.el @@ -349,7 +349,7 @@ For example, you can set it to like `isearch-exit'." :version "28.1") (defcustom repeat-exit-timeout nil - "Break the repetition chain of keys after specified timeout. + "Break the repetition chain of keys after specified amount of idle time. When a number, exit the transient repeating mode after idle time of the specified number of seconds. You can also set the property `repeat-exit-timeout' on the command symbol. @@ -380,12 +380,12 @@ This property can override the value of this variable." (defcustom repeat-check-key t "Whether to check that the last key exists in the repeat map. -When non-nil and the last typed key (with or without modifiers) -doesn't exist in the keymap attached by the `repeat-map' property, -then don't activate that keymap for the next command. So only the -same keys among repeatable keys are allowed in the repeating sequence. -For example, with a non-nil value, only \\`C-x u u' repeats undo, -whereas \\`C-/ u' doesn't. +When non-nil, and the last typed key (with or without modifiers) +doesn't exist in the keymap specified by the `repeat-map' property +of the command, don't activate that keymap for the next command. +Thus, when this is non-nil, only the same keys among repeatable +keys are allowed in the repeating sequence. For example, with a +non-nil value, only \\`C-x u u' repeats undo, whereas \\`C-/ u' doesn't. You can also set the property `repeat-check-key' on the command symbol. This property can override the value of this variable. @@ -398,7 +398,7 @@ but the property value is `t', then check the last key." (defcustom repeat-echo-function #'repeat-echo-message "Function to display a hint about available keys. -Function is called after every repeatable command with one argument: +The function is called after every repeatable command with one argument: a repeating map, or nil after deactivating the transient repeating mode. You can use `add-function' for multiple functions simultaneously." :type '(choice (const :tag "Show hints in the echo area" @@ -422,8 +422,12 @@ the map can't be set on the command symbol property `repeat-map'.") ;;;###autoload (define-minor-mode repeat-mode "Toggle Repeat mode. -When Repeat mode is enabled, and the command symbol has the property named -`repeat-map', this map is activated temporarily for the next command. +When Repeat mode is enabled, certain commands bound to multi-key +sequences can be repeated by typing a single key, after typing the +full key sequence once. +The commands which can be repeated like that are those whose symbol + has the property `repeat-map' which specifies a keymap of single +keys for repeating. See `describe-repeat-maps' for a list of all repeatable commands." :global t :group 'repeat (if (not repeat-mode) @@ -459,7 +463,7 @@ See `describe-repeat-maps' for a list of all repeatable commands." rep-map)))) (defun repeat-check-key (key map) - "Check if the last key is suitable to activate the repeating MAP." + "Check if the last KEY is suitable for activating the repeating MAP." (let* ((prop (repeat--command-property 'repeat-check-key)) (check-key (unless (eq prop 'no) (or prop repeat-check-key)))) (or (not check-key) @@ -471,7 +475,7 @@ See `describe-repeat-maps' for a list of all repeatable commands." "Previous minibuffer state.") (defun repeat-check-map (map) - "Decides whether MAP can be used for the next command." + "Decide whether MAP can be used for the next command." (and map ;; Detect changes in the minibuffer state to allow repetitions ;; in the same minibuffer, but not when the minibuffer is activated @@ -547,7 +551,7 @@ This function can be used to force exit of repetition while it's active." (setq repeat-exit-function nil))) (defun repeat-echo-message-string (keymap) - "Return a string with a list of repeating keys." + "Return a string with the list of repeating keys in KEYMAP." (let (keys) (map-keymap (lambda (key cmd) (and cmd (push key keys))) keymap) (format-message "Repeat with %s%s" @@ -565,7 +569,8 @@ This function can be used to force exit of repetition while it's active." "")))) (defun repeat-echo-message (keymap) - "Display available repeating keys in the echo area." + "Display in the echo area the repeating keys defined by KEYMAP. +See `repeat-echo-function' to enable/disable." (let ((message-log-max nil)) (if keymap (let ((message (repeat-echo-message-string keymap))) @@ -586,7 +591,9 @@ This function can be used to force exit of repetition while it's active." "String displayed in the mode line in repeating mode.") (defun repeat-echo-mode-line (keymap) - "Display the repeat indicator in the mode line." + "Display the repeat indicator in the mode line. +KEYMAP should be non-nil, but is otherwise ignored. +See `repeat-echo-function' to enable/disable." (if keymap (unless (assq 'repeat-in-progress mode-line-modes) (add-to-list 'mode-line-modes (list 'repeat-in-progress @@ -596,9 +603,11 @@ This function can be used to force exit of repetition while it's active." (declare-function help-fns--analyze-function "help-fns" (function)) (defun describe-repeat-maps () - "Describe mappings of commands repeatable by symbol property `repeat-map'. -If `repeat-mode' is enabled, these keymaps determine which single key -can be used to repeat a command invoked via a full key sequence." + "Describe transient keymaps installed for repeating multi-key commands. +These keymaps enable repetition of commands bound to multi-key +sequences by typing just one key, when `repeat-mode' is enabled. +Commands that can be repeated this way must have their symbol +to have the `repeat-map' property whose value specified a keymap." (interactive) (require 'help-fns) (let ((help-buffer-under-preparation t)) @@ -613,7 +622,9 @@ can be used to repeat a command invoked via a full key sequence." (with-help-window (help-buffer) (with-current-buffer standard-output (setq-local outline-regexp "[*]+") - (insert "A list of keymaps used by commands with the symbol property `repeat-map'.\n") + (insert "\ +A list of keymaps and their single-key shortcuts for repeating commands. +Click on a keymap to see the commands repeatable by the keymap.\n") (dolist (keymap (sort keymaps (lambda (a b) (when (and (symbolp (car a)) diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el index 119a243d6b3..dce6fa735fc 100644 --- a/lisp/tab-bar.el +++ b/lisp/tab-bar.el @@ -2624,14 +2624,14 @@ When `switch-to-buffer-obey-display-actions' is non-nil, (keymap-set tab-prefix-map "t" #'other-tab-prefix) (defvar-keymap tab-bar-switch-repeat-map - :doc "Keymap to repeat tab switch key sequences \\`C-x t o o O'. + :doc "Keymap to repeat tab switch commands `tab-next' and `tab-previous'. Used in `repeat-mode'." :repeat t "o" #'tab-next "O" #'tab-previous) (defvar-keymap tab-bar-move-repeat-map - :doc "Keymap to repeat tab move key sequences \\`C-x t m m M'. + :doc "Keymap to repeat tab move commands `tab-move' and `tab-bar-move-tab-backward'. Used in `repeat-mode'." :repeat t "m" #'tab-move diff --git a/lisp/window.el b/lisp/window.el index 0cd30822ff6..2d9f746d8fb 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -10567,8 +10567,7 @@ displaying that processes's buffer." (define-key ctl-x-4-map "4" 'other-window-prefix) (defvar-keymap other-window-repeat-map - :doc "Keymap to repeat `other-window' key sequences. -Used in `repeat-mode'." + :doc "Keymap to repeat `other-window'. Used in `repeat-mode'." :repeat t "o" #'other-window "O" (lambda () @@ -10578,6 +10577,8 @@ Used in `repeat-mode'." (defvar-keymap resize-window-repeat-map :doc "Keymap to repeat window resizing commands. +Repeatable commands are `enlarge-window' and `shrink-window', +and also `enlarge-window-horizontally' and `shrink-window-horizontally'. Used in `repeat-mode'." :repeat t ;; Standard keys: From f6955482c2933706229044c04d88b807b63a7095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= Date: Tue, 31 Jan 2023 11:15:13 +0100 Subject: [PATCH 06/23] Clean up LAP peephole logging Make `byte-compile-log-lap` more robust and produce nicer output. This is of interest for Elisp compiler maintainers only. * lisp/emacs-lisp/byte-opt.el (bytecomp--log-lap-arg): New. (byte-compile-log-lap-1): Extract argument conversion and rewrite in a more modern way, fixing bugs. In particular, tags are now displayed as "X:" where X is the tag number, and that tag number is shown as argument to goto-like ops. (byte-optimize-lapcode): Clean up and simplify logging, producing useful information when `byte-optimize-log` is `byte` as intended. --- lisp/emacs-lisp/byte-opt.el | 83 ++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 42 deletions(-) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 4d39e28fc8e..9eb48f5fe0b 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -72,34 +72,40 @@ (require 'macroexp) (eval-when-compile (require 'subr-x)) +(defun bytecomp--log-lap-arg (arg) + ;; Convert an argument that may be a LAP operation to something printable. + (cond + ;; Symbols are just stripped of their -byte prefix if any. + ((symbolp arg) + (intern (string-remove-prefix "byte-" (symbol-name arg)))) + ;; Conses are assumed to be LAP ops or tags. + ((and (consp arg) (symbolp (car arg))) + (let* ((head (car arg)) + (tail (cdr arg)) + (op (intern (string-remove-prefix "byte-" (symbol-name head))))) + (cond + ((eq head 'TAG) + (format "%d:" (car tail))) + ((memq head byte-goto-ops) + (format "(%s %d)" op (cadr tail))) + ((memq head byte-constref-ops) + (format "(%s %s)" + (if (eq op 'constant) 'const op) + (if (numberp tail) + (format "" tail) ; closure var reference + (format "%S" (car tail))))) ; actual constant + ;; Ops with an immediate argument. + ((memq op '( stack-ref stack-set call unbind + listN concatN insertN discardN discardN-preserve-tos)) + (format "(%s %S)" op tail)) + ;; Without immediate, print just the symbol. + (t op)))) + ;; Anything else is printed as-is. + (t arg))) + (defun byte-compile-log-lap-1 (format &rest args) (byte-compile-log-1 - (apply #'format-message format - (let (c a) - (mapcar (lambda (arg) - (if (not (consp arg)) - (if (and (symbolp arg) - (string-match "^byte-" (symbol-name arg))) - (intern (substring (symbol-name arg) 5)) - arg) - (if (integerp (setq c (car arg))) - (error "Non-symbolic byte-op %s" c)) - (if (eq c 'TAG) - (setq c arg) - (setq a (cond ((memq c byte-goto-ops) - (car (cdr (cdr arg)))) - ((memq c byte-constref-ops) - (car (cdr arg))) - (t (cdr arg)))) - (setq c (symbol-name c)) - (if (string-match "^byte-." c) - (setq c (intern (substring c 5))))) - (if (eq c 'constant) (setq c 'const)) - (if (and (eq (cdr arg) 0) - (not (memq c '(unbind call const)))) - c - (format "(%s %s)" c a)))) - args))))) + (apply #'format-message format (mapcar #'bytecomp--log-lap-arg args)))) (defmacro byte-compile-log-lap (format-string &rest args) `(and (memq byte-optimize-log '(t byte)) @@ -2073,10 +2079,8 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (setcar lap0 (setq tmp 'byte-discard)) (setcdr lap0 0)) ((error "Depth conflict at tag %d" (nth 2 lap0)))) - (and (memq byte-optimize-log '(t byte)) - (byte-compile-log " (goto %s) %s:\t-->\t%s %s:" - (nth 1 lap1) (nth 1 lap1) - tmp (nth 1 lap1))) + (byte-compile-log-lap " %s %s\t-->\t%s %s" + lap0 lap1 tmp lap1) (setq keep-going t)) ;; ;; varset-X varref-X --> dup varset-X @@ -2165,7 +2169,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (eq (cdr lap0) lap2)) ; TAG X (let ((inverse (if (eq 'byte-goto-if-nil (car lap0)) 'byte-goto-if-not-nil 'byte-goto-if-nil))) - (byte-compile-log-lap " %s %s %s:\t-->\t%s %s:" + (byte-compile-log-lap " %s %s %s\t-->\t%s %s" lap0 lap1 lap2 (cons inverse (cdr lap1)) lap2) (setq lap (delq lap0 lap)) @@ -2238,9 +2242,8 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; ((and (eq (car lap0) 'TAG) (eq (car lap1) 'TAG)) - (and (memq byte-optimize-log '(t byte)) - (byte-compile-log " adjacent tags %d and %d merged" - (nth 1 lap1) (nth 1 lap0))) + (byte-compile-log-lap " adjacent tags %d and %d merged" + (nth 1 lap1) (nth 1 lap0)) (setq tmp3 lap) (while (setq tmp2 (rassq lap0 tmp3)) (setcdr tmp2 lap1) @@ -2262,8 +2265,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (cl-loop for table in byte-compile-jump-tables when (member lap0 (hash-table-values table)) return nil finally return t)) - (and (memq byte-optimize-log '(t byte)) - (byte-compile-log " unused tag %d removed" (nth 1 lap0))) + (byte-compile-log-lap " unused tag %d removed" (nth 1 lap0)) (setq lap (delq lap0 lap) keep-going t)) ;; @@ -2459,12 +2461,10 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (memq (car (car tmp)) '(byte-goto byte-goto-if-nil byte-goto-if-not-nil byte-goto-if-nil-else-pop))) - ;; (byte-compile-log-lap " %s %s, %s %s --> moved conditional" - ;; lap0 lap1 (cdr lap0) (car tmp)) (let ((newtag (byte-compile-make-tag))) (byte-compile-log-lap - "%s %s: ... %s: %s\t-->\t%s ... %s:" - lap0 (nth 1 lap1) (nth 1 (cdr lap0)) (car tmp) + " %s %s ... %s %s\t-->\t%s ... %s" + lap0 lap1 (cdr lap0) (car tmp) (cons (cdr (assq (car (car tmp)) '((byte-goto-if-nil . byte-goto-if-not-nil) (byte-goto-if-not-nil . byte-goto-if-nil) @@ -2474,8 +2474,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." byte-goto-if-nil-else-pop)))) newtag) - (nth 1 newtag) - ) + newtag) (setcdr tmp (cons (setcdr lap0 newtag) (cdr tmp))) (if (eq (car (car tmp)) 'byte-goto-if-nil-else-pop) ;; We can handle this case but not the -if-not-nil case, From bfd338aad9d1e6bf898fc19d23e1a5ca4e696316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Engdeg=C3=A5rd?= Date: Wed, 18 Jan 2023 18:36:29 +0100 Subject: [PATCH 07/23] LAP peephole optimisation improvements - Since discardN-preserve-tos(1) and stack-set(1) have the same effect, treat them as equivalent in all transformations. - Move the rule discardN-preserve-tos(X) discardN-preserve-tos(Y) --> discardN-preserve-tos(X+Y) from the final pass to the main iteration since it may enable further optimisations. - Don't apply the rule goto(X) ... X: DISCARD --> DISCARD goto(Y) ... X: DISCARD Y: when DISCARD could be merged or deleted instead, which is even better. - Add the rule OP const return -> const return where OP is effect-free. - Generalise the push-pop annihilation rule to PUSH(K) discard(N) -> discard(N-K), N>K PUSH(K) discard(N) -> , N=K to any N, not just N=1. - Add the rule OP goto(X) Y: OP X: -> Y: OP X: for any operation OP. * lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode): Make the changes described above. --- lisp/emacs-lisp/byte-opt.el | 128 +++++++++++++++++++++++++----------- 1 file changed, 90 insertions(+), 38 deletions(-) diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el index 9eb48f5fe0b..861cf95b1ff 100644 --- a/lisp/emacs-lisp/byte-opt.el +++ b/lisp/emacs-lisp/byte-opt.el @@ -2042,31 +2042,29 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; optimized but sequences like "dup varset TAG1: discard" are not. ;; You may be tempted to change this; resist that temptation. (cond - ;; pop --> - ;; ...including: - ;; const-X pop --> - ;; varref-X pop --> - ;; dup pop --> - ;; - ((and (eq 'byte-discard (car lap1)) + ;; + ;; PUSH(K) discard(N) --> discard(N-K), N>K + ;; PUSH(K) discard(N) --> , N=K + ;; where PUSH(K) is a side-effect-free op such as const, varref, dup + ;; + ((and (memq (car lap1) '(byte-discard byte-discardN)) (memq (car lap0) side-effect-free)) (setq keep-going t) - (setq tmp (aref byte-stack+-info (symbol-value (car lap0)))) - (setq rest (cdr rest)) - (cond ((eql tmp 1) - (byte-compile-log-lap - " %s discard\t-->\t" lap0) - (setq lap (delq lap0 (delq lap1 lap)))) - ((eql tmp 0) - (byte-compile-log-lap - " %s discard\t-->\t discard" lap0) - (setq lap (delq lap0 lap))) - ((eql tmp -1) - (byte-compile-log-lap - " %s discard\t-->\tdiscard discard" lap0) - (setcar lap0 'byte-discard) - (setcdr lap0 0)) - (t (error "Optimizer error: too much on the stack")))) + (let* ((pushes (aref byte-stack+-info (symbol-value (car lap0)))) + (pops (if (eq (car lap1) 'byte-discardN) (cdr lap1) 1)) + (net-pops (- pops pushes))) + (cond ((= net-pops 0) + (byte-compile-log-lap " %s %s\t-->\t" lap0 lap1) + (setcdr rest (cddr rest)) + (setq lap (delq lap0 lap))) + ((> net-pops 0) + (byte-compile-log-lap + " %s %s\t-->\t discard(%d)" lap0 lap1 net-pops) + (setcar rest (if (eql net-pops 1) + (cons 'byte-discard nil) + (cons 'byte-discardN net-pops))) + (setcdr rest (cddr rest))) + (t (error "Optimizer error: too much on the stack"))))) ;; ;; goto*-X X: --> X: ;; @@ -2353,6 +2351,40 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (setcar lap0 'byte-return)) (setcdr lap0 (cdr tmp)) (setq keep-going t)))) + + ;; + ;; OP goto(X) Y: OP X: -> Y: OP X: + ;; + ((and (eq (car lap1) 'byte-goto) + (eq (car lap2) 'TAG) + (let ((lap3 (nth 3 rest))) + (and (eq (car lap0) (car lap3)) + (eq (cdr lap0) (cdr lap3)) + (eq (cdr lap1) (nth 4 rest))))) + (byte-compile-log-lap " %s %s %s %s %s\t-->\t%s %s %s" + lap0 lap1 lap2 + (nth 3 rest) (nth 4 rest) + lap2 (nth 3 rest) (nth 4 rest)) + (setcdr rest (cddr rest)) + (setq lap (delq lap0 lap)) + (setq keep-going t)) + + ;; + ;; OP const return --> const return + ;; where OP is side-effect-free (or mere stack manipulation). + ;; + ((and (eq (car lap1) 'byte-constant) + (eq (car (nth 2 rest)) 'byte-return) + (or (memq (car lap0) '( byte-discard byte-discardN + byte-discardN-preserve-tos + byte-stack-set)) + (memq (car lap0) side-effect-free))) + (setq keep-going t) + (setq add-depth 1) ; in case we get rid of too much stack reduction + (setq lap (delq lap0 lap)) + (byte-compile-log-lap " %s %s %s\t-->\t%s %s" + lap0 lap1 (nth 2 rest) lap1 (nth 2 rest))) + ;; ;; goto-*-else-pop X ... X: goto-if-* --> whatever ;; goto-*-else-pop X ... X: discard --> whatever @@ -2491,6 +2523,24 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ) (setq keep-going t)) + ;; + ;; discardN-preserve-tos(X) discardN-preserve-tos(Y) + ;; --> discardN-preserve-tos(X+Y) + ;; where stack-set(1) is accepted as discardN-preserve-tos(1) + ;; + ((and (or (eq (car lap0) 'byte-discardN-preserve-tos) + (and (eq (car lap0) 'byte-stack-set) (eql (cdr lap0) 1))) + (or (eq (car lap1) 'byte-discardN-preserve-tos) + (and (eq (car lap1) 'byte-stack-set) (eql (cdr lap1) 1)))) + (setq keep-going t) + (let ((new-op (cons 'byte-discardN-preserve-tos + ;; This happens to work even when either + ;; op is stack-set(1). + (+ (cdr lap0) (cdr lap1))))) + (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 new-op) + (setcar rest new-op) + (setcdr rest (cddr rest)))) + ;; ;; stack-set-M [discard/discardN ...] --> discardN-preserve-tos ;; stack-set-M [discard/discardN ...] --> discardN @@ -2529,7 +2579,7 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; ;; discardN-preserve-tos return --> return ;; dup return --> return - ;; stack-set-N return --> return ; where N is TOS-1 + ;; stack-set(1) return --> return ;; ((and (eq (car lap1) 'byte-return) (or (memq (car lap0) '(byte-discardN-preserve-tos byte-dup)) @@ -2546,8 +2596,15 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; ((and (eq (car lap0) 'byte-goto) (setq tmp (cdr (memq (cdr lap0) lap))) - (memq (caar tmp) '(byte-discard byte-discardN - byte-discardN-preserve-tos))) + (or (memq (caar tmp) '(byte-discard byte-discardN)) + ;; Make sure we don't hoist a discardN-preserve-tos + ;; that really should be merged or deleted instead. + (and (eq (caar tmp) 'byte-discardN-preserve-tos) + (let ((next (cadr tmp))) + (not (or (memq (car next) '(byte-discardN-preserve-tos + byte-return)) + (and (eq (car next) 'byte-stack-set) + (eql (cdr next) 1)))))))) (byte-compile-log-lap " goto-X .. X: \t-->\t%s goto-X.. X: %s Y:" (car tmp) (car tmp)) @@ -2562,11 +2619,16 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." ;; ;; const discardN-preserve-tos ==> discardN const + ;; const stack-set(1) ==> discard const ;; ((and (eq (car lap0) 'byte-constant) - (eq (car lap1) 'byte-discardN-preserve-tos)) + (or (eq (car lap1) 'byte-discardN-preserve-tos) + (and (eq (car lap1) 'byte-stack-set) + (eql (cdr lap1) 1)))) (setq keep-going t) - (let ((newdiscard (cons 'byte-discardN (cdr lap1)))) + (let ((newdiscard (if (eql (cdr lap1) 1) + (cons 'byte-discard nil) + (cons 'byte-discardN (cdr lap1))))) (byte-compile-log-lap " %s %s\t-->\t%s %s" lap0 lap1 newdiscard lap0) (setf (car rest) newdiscard) @@ -2651,16 +2713,6 @@ If FOR-EFFECT is non-nil, the return value is assumed to be of no importance." (setcdr lap1 (+ (if (eq (car lap0) 'byte-discard) 1 (cdr lap0)) (if (eq (car lap1) 'byte-discard) 1 (cdr lap1)))) (setcar lap1 'byte-discardN)) - - ;; - ;; discardN-preserve-tos-X discardN-preserve-tos-Y --> - ;; discardN-preserve-tos-(X+Y) - ;; - ((and (eq (car lap0) 'byte-discardN-preserve-tos) - (eq (car lap1) 'byte-discardN-preserve-tos)) - (setq lap (delq lap0 lap)) - (setcdr lap1 (+ (cdr lap0) (cdr lap1))) - (byte-compile-log-lap " %s %s\t-->\t%s" lap0 lap1 (car rest))) ) (setq rest (cdr rest))) (setq byte-compile-maxdepth (+ byte-compile-maxdepth add-depth))) From 2de0ab5cbd35666276b9150d14611c6aa5678f3d Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 2 Feb 2023 16:14:15 +0200 Subject: [PATCH 08/23] ; Doc fixes in keymap.el * lisp/keymap.el (key-valid-p, key-translate, keymap-lookup) (define-keymap): Doc fixes. --- lisp/keymap.el | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lisp/keymap.el b/lisp/keymap.el index de90b03ba64..201a49cef8c 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -290,26 +290,26 @@ See `kbd' for a descripion of KEYS." res))) (defun key-valid-p (keys) - "Say whether KEYS is a valid key. -A key is a string consisting of one or more key strokes. -The key strokes are separated by single space characters. + "Return non-nil if KEYS, a string, is a valid key sequence. +KEYS should be a string consisting of one or more key strokes, +with a single space character separating one key stroke from another. Each key stroke is either a single character, or the name of an -event, surrounded by angle brackets. In addition, any key stroke -may be preceded by one or more modifier keys. Finally, a limited -number of characters have a special shorthand syntax. +event, surrounded by angle brackets . In addition, any +key stroke may be preceded by one or more modifier keys. Finally, +a limited number of characters have a special shorthand syntax. -Here's some example key sequences. +Here are some example of valid key sequences. \"f\" (the key `f') - \"S o m\" (a three key sequence of the keys `S', `o' and `m') - \"C-c o\" (a two key sequence of the keys `c' with the control modifier - and then the key `o') - \"H-\" (the key named \"left\" with the hyper modifier) + \"S o m\" (a three-key sequence of the keys `S', `o' and `m') + \"C-c o\" (a two-key sequence: the key `c' with the control modifier + followed by the key `o') + \"H-\" (the function key named \"left\" with the hyper modifier) \"M-RET\" (the \"return\" key with a meta modifier) \"C-M-\" (the \"space\" key with both the control and meta modifiers) -These are the characters that have shorthand syntax: +These are the characters that have special shorthand syntax: NUL, RET, TAB, LFD, ESC, SPC, DEL. Modifiers have to be specified in this order: @@ -358,7 +358,7 @@ which is This function creates a `keyboard-translate-table' if necessary and then modifies one entry in it. -Both KEY and TO are strings that satisfy `key-valid-p'." +Both KEY and TO should be specified by strings that satisfy `key-valid-p'." (declare (compiler-macro (lambda (form) (keymap--compile-check from to) form))) (keymap--check from) @@ -369,7 +369,7 @@ Both KEY and TO are strings that satisfy `key-valid-p'." (aset keyboard-translate-table (key-parse from) (key-parse to))) (defun keymap-lookup (keymap key &optional accept-default no-remap position) - "Return the binding for command KEY. + "Return the binding for command KEY in KEYMAP. KEY is a string that satisfies `key-valid-p'. If KEYMAP is nil, look up in the current keymaps. If non-nil, it @@ -391,15 +391,15 @@ in the current keymaps. However, if the optional third argument NO-REMAP is non-nil, `keymap-lookup' returns the unmapped command. -If KEY is a key sequence initiated with the mouse, the used keymaps -will depend on the clicked mouse position with regard to the buffer -and possible local keymaps on strings. +If KEY is a mouse gesture, the keymaps used depend on the clicked +mouse position with regards to the buffer, and local keymaps, if any, +on display and overlay strings. If the optional argument POSITION is non-nil, it specifies a mouse position as returned by `event-start' and `event-end', and the lookup occurs in the keymaps associated with it instead of KEY. It can also be a number or marker, in which case the keymap properties at the -specified buffer position instead of point are used." +specified buffer position are used instead of point." (declare (compiler-macro (lambda (form) (keymap--compile-check key) form))) (keymap--check key) (when (and keymap position) @@ -475,7 +475,7 @@ If MESSAGE (and interactively), message the result." (defun define-keymap (&rest definitions) "Create a new keymap and define KEY/DEFINITION pairs as key bindings. -The new keymap is returned. +Return the new keymap. Options can be given as keywords before the KEY/DEFINITION pairs. Available keywords are: From 1c125baa3f0d908eaf19698bbef2e81653e4f421 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Thu, 2 Feb 2023 19:41:09 +0200 Subject: [PATCH 09/23] Teach 'hs-minor-mode' about tree-sitter based modes * lisp/progmodes/hideshow.el (hs-special-modes-alist): Teach 'hs-minor-mode' about tree-sitter based modes. (Bug#61232) --- lisp/progmodes/hideshow.el | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el index c160e6ad1df..b878986d7a4 100644 --- a/lisp/progmodes/hideshow.el +++ b/lisp/progmodes/hideshow.el @@ -256,10 +256,14 @@ This has effect only if `search-invisible' is set to `open'." (defvar hs-special-modes-alist (mapcar #'purecopy '((c-mode "{" "}" "/[*/]" nil nil) + (c-ts-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) + (c++-ts-mode "{" "}" "/[*/]" nil nil) (bibtex-mode ("@\\S(*\\(\\s(\\)" 1)) (java-mode "{" "}" "/[*/]" nil nil) + (java-ts-mode "{" "}" "/[*/]" nil nil) (js-mode "{" "}" "/[*/]" nil) + (js-ts-mode "{" "}" "/[*/]" nil) (mhtml-mode "{\\|<[^/>]*?" "}\\|]*[^/]>" "