emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android bfce0ce57f 3/3: Merge remote-tracking branch 'origin/mas


From: Po Lu
Subject: feature/android bfce0ce57f 3/3: Merge remote-tracking branch 'origin/master' into feature/android
Date: Sat, 4 Feb 2023 06:55:24 -0500 (EST)

branch: feature/android
commit bfce0ce57fe0de11a6cbe3ff878a59dd2a0853d4
Merge: 9ffb5c0cf3 0a95a81d8d
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Merge remote-tracking branch 'origin/master' into feature/android
---
 admin/notes/tree-sitter/treesit_record_change      |  50 +++++
 doc/emacs/basic.texi                               |  49 +++--
 doc/emacs/building.texi                            |  46 +++--
 etc/NEWS.29                                        |  26 +++
 lisp/bindings.el                                   |   6 +-
 lisp/emacs-lisp/byte-opt.el                        | 211 +++++++++++++--------
 lisp/emacs-lisp/lisp-mode.el                       |   1 +
 lisp/eshell/em-cmpl.el                             |  43 ++---
 lisp/faces.el                                      |  11 +-
 lisp/keymap.el                                     |  38 ++--
 lisp/progmodes/c-ts-common.el                      |  35 ++--
 lisp/progmodes/c-ts-mode.el                        |  54 ++++--
 lisp/progmodes/cc-engine.el                        |  60 +++---
 lisp/progmodes/hideshow.el                         |   4 +
 lisp/progmodes/ruby-ts-mode.el                     |   5 +-
 lisp/repeat.el                                     |  48 +++--
 lisp/simple.el                                     |  22 ++-
 lisp/tab-bar.el                                    |   4 +-
 lisp/window.el                                     |   5 +-
 src/insdel.c                                       |  19 +-
 src/lisp.h                                         |   3 +
 src/search.c                                       |   5 +-
 src/sqlite.c                                       |  10 +-
 src/treesit.c                                      |  43 ++++-
 src/xfaces.c                                       |   3 +-
 .../progmodes/c-ts-mode-resources/indent-bsd.erts  |   6 +-
 .../lisp/progmodes/c-ts-mode-resources/indent.erts |  64 +++----
 27 files changed, 564 insertions(+), 307 deletions(-)

diff --git a/admin/notes/tree-sitter/treesit_record_change 
b/admin/notes/tree-sitter/treesit_record_change
new file mode 100644
index 0000000000..bb0f9edc35
--- /dev/null
+++ b/admin/notes/tree-sitter/treesit_record_change
@@ -0,0 +1,50 @@
+NOTES ON TREESIT_RECORD_CHANGE
+
+It is vital that Emacs informs tree-sitter of every change made to the
+buffer, lest tree-sitter's parse tree would be corrupted/out of sync.
+
+All buffer changes in Emacs are made through functions in insdel.c
+(and casefiddle.c), I augmented functions in those files with calls to
+treesit_record_change.  Below is a manifest of all the relavent
+functions in insdel.c as of Emacs 29:
+
+Function                          Calls
+----------------------------------------------------------------------
+copy_text                         (*1)
+insert                            insert_1_both
+insert_and_inherit                insert_1_both
+insert_char                       insert
+insert_string                     insert
+insert_before_markers             insert_1_both
+insert_before_markers_and_inherit insert_1_both
+insert_1_both                     treesit_record_change
+insert_from_string                insert_from_string_1
+insert_from_string_before_markers insert_from_string_1
+insert_from_string_1              treesit_record_change
+insert_from_gap_1                 treesit_record_change
+insert_from_gap                   insert_from_gap_1
+insert_from_buffer                treesit_record_change
+insert_from_buffer_1              (used by insert_from_buffer) (*2)
+replace_range                     treesit_record_change
+replace_range_2                   (caller needs to call treesit_r_c)
+del_range                         del_range_1
+del_range_1                       del_range_2
+del_range_byte                    del_range_2
+del_range_both                    del_range_2
+del_range_2                       treesit_record_change
+
+(*1) This functions is used only to copy from string to string when
+used outside of insdel.c, and when used inside insdel.c, the caller
+calls treesit_record_change.
+
+(*2) This function is a static function, and insert_from_buffer is its
+only caller.  So it should be fine to call treesit_record_change in
+insert_from_buffer but not insert_from_buffer_1.  I also left a
+reminder comment.
+
+
+As for casefiddle.c, do_casify_unibyte_region and
+do_casify_multibyte_region modifies buffer, but they are static
+functions and are called by casify_region, which calls
+treesit_record_change.  Other higher-level functions calls
+casify_region to do the work.
\ No newline at end of file
diff --git a/doc/emacs/basic.texi b/doc/emacs/basic.texi
index 2cc45a8805..a271cb65bd 100644
--- a/doc/emacs/basic.texi
+++ b/doc/emacs/basic.texi
@@ -887,19 +887,40 @@ 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
-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, 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.
+  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 repetition mode will be turned off automatically.
diff --git a/doc/emacs/building.texi b/doc/emacs/building.texi
index 98f67ddd9d..3f6a418de1 100644
--- a/doc/emacs/building.texi
+++ b/doc/emacs/building.texi
@@ -961,9 +961,7 @@ the fringe of a source buffer to set a breakpoint there.
 @vindex gud-gdb-command-name
   To run GDB using just the GUD interaction buffer interface, without
 these additional features, use @kbd{M-x gud-gdb} (@pxref{Starting
-GUD}).  You must use this if you want to debug multiple programs
-within one Emacs session, as that is currently unsupported by @kbd{M-x
-gdb}.
+GUD}).
 
   Internally, @kbd{M-x gdb} informs GDB that its screen size is
 unlimited; for correct operation, you must not change GDB's screen
@@ -1051,9 +1049,9 @@ to restore only when @code{gdb-show-main} is 
non-@code{nil}.
   You may also specify additional GDB-related buffers to display,
 either in the same frame or a different one.  Select the buffers you
 want by typing @kbd{M-x gdb-display-@var{buffertype}-buffer} or
-@kbd{M-x gdb-frame-@var{buffertype}-buffer}, where @var{buffertype}
-is the relevant buffer type, such as @samp{breakpoints}.  You can do
-the same with the menu bar, with the @samp{GDB-Windows} and
+@kbd{M-x gdb-frame-@var{buffertype}-buffer}, where @var{buffertype} is
+the relevant buffer type, such as @samp{breakpoints} or @samp{io}.
+You can do the same from the menu bar, with the @samp{GDB-Windows} and
 @samp{GDB-Frames} sub-menus of the @samp{GUD} menu.
 
 @vindex gdb-max-source-window-count
@@ -1273,10 +1271,14 @@ non-@code{nil} value.
 @node Other GDB Buffers
 @subsubsection Other GDB Buffers
 
+Other buffers provided by @kbd{M-x gdb} whose display you can
+optionally request include:
+
 @table @asis
+@findex gdb-display-locals-buffer
 @item Locals Buffer
 This buffer displays the values of local variables of the current
-frame for simple data types (@pxref{Frame Info, Frame Info,
+stack frame for simple data types (@pxref{Frame Info, Frame Info,
 Information on a frame, gdb, The GNU debugger}).  Press @key{RET} or
 click @kbd{mouse-2} on the value if you want to edit it.
 
@@ -1286,20 +1288,35 @@ you can examine the value of the local variable at 
point by typing
 GDB, use @key{RET} or @kbd{mouse-2} on the type description
 (@samp{[struct/union]} or @samp{[array]}).  @xref{Watch Expressions}.
 
+To display the Locals buffer, type @kbd{M-x gdb-display-locals-buffer}.
+
+@findex gdb-display-io-buffer
+@item I/O Buffer
+If the program you are debugging uses standard input and output
+streams for interaction with the user, or emits a significant amount
+of output to its standard output, you may wish to separate its I/O
+from interaction with GDB.  Use the command @w{@kbd{M-x
+gdb-display-io-buffer}} to show a window with a buffer to which Emacs
+redirects the input and output from the program you are debugging.
+
+@findex gdb-display-registers-buffer
 @item Registers Buffer
-@findex toggle-gdb-all-registers
 This buffer displays the values held by the registers
-(@pxref{Registers,,, gdb, The GNU debugger}).  Press @key{RET} or
-click @kbd{mouse-2} on a register if you want to edit its value.  With
-GDB 6.4 or later, recently changed register values display with
-@code{font-lock-warning-face}.
+(@pxref{Registers,,, gdb, The GNU debugger}).  Request the display of
+this buffer with the command @kbd{M-x gdb-display-registers-buffer}.
+Press @key{RET} or click @kbd{mouse-2} on a register if you want to
+edit its value.  With GDB 6.4 or later, recently changed register
+values display with @code{font-lock-warning-face}.
 
+@findex gdb-display-disassembly-buffer
 @item Assembler Buffer
 The assembler buffer displays the current frame as machine code.  An
 arrow points to the current instruction, and you can set and remove
 breakpoints as in a source buffer.  Breakpoint icons also appear in
-the fringe or margin.
+the fringe or margin.  To request the display of this buffer, use
+@kbd{M-x gdb-display-disassembly-buffer}.
 
+@findex gdb-display-memory-buffer
 @item Memory Buffer
 The memory buffer lets you examine sections of program memory
 (@pxref{Memory, Memory, Examining memory, gdb, The GNU debugger}).
@@ -1307,7 +1324,8 @@ Click @kbd{mouse-1} on the appropriate part of the header 
line to
 change the starting address or number of data items that the buffer
 displays.  Alternatively, use @kbd{S} or @kbd{N} respectively.  Click
 @kbd{mouse-3} on the header line to select the display format or unit
-size for these data items.
+size for these data items.  Use @w{@kbd{M-x
+gdb-display-memory-buffer}} to request display of this buffer.
 @end table
 
 When @code{gdb-many-windows} is non-@code{nil}, the locals buffer
diff --git a/etc/NEWS.29 b/etc/NEWS.29
index fb211f9b7d..e3cbeb84d3 100644
--- a/etc/NEWS.29
+++ b/etc/NEWS.29
@@ -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
 
@@ -1339,6 +1353,18 @@ dragged.
 Customize this option to limit the number of entries in the menu
 "Edit → Paste from Kill Menu".  The default is 60.
 
+---
+** New user option 'copy-region-blink-predicate'.
+By default, when copying a region with 'kill-ring-save', Emacs only
+blinks point and mark when the region is not denoted visually, that
+is, when either the region is inactive, or the 'region' face is
+indistinguishable from the 'default' face.
+
+Users who would rather enable blinking unconditionally can now set
+this user option to 'always'.  To disable blinking unconditionally,
+either set this option to 'ignore', or set 'copy-region-blink-delay'
+to 0.
+
 +++
 ** Performing a pinch gesture on a touchpad now increases the text scale.
 
diff --git a/lisp/bindings.el b/lisp/bindings.el
index 99189d2e57..c77b64c05d 100644
--- a/lisp/bindings.el
+++ b/lisp/bindings.el
@@ -1011,7 +1011,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)
 
@@ -1108,7 +1108,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
@@ -1470,7 +1470,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/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 4d39e28fc8..861cf95b1f 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 "<V%d>" 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))
@@ -2036,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
-        ;; <side-effect-free> pop -->  <deleted>
-        ;;  ...including:
-        ;; const-X pop   -->  <deleted>
-        ;; varref-X pop  -->  <deleted>
-        ;; dup pop       -->  <deleted>
-        ;;
-        ((and (eq 'byte-discard (car lap1))
+         ;;
+         ;; PUSH(K) discard(N) -->  <deleted> discard(N-K), N>K
+         ;; PUSH(K) discard(N) -->  <deleted>,              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<deleted>" lap0)
-                (setq lap (delq lap0 (delq lap1 lap))))
-               ((eql tmp 0)
-                (byte-compile-log-lap
-                 "  %s discard\t-->\t<deleted> 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<deleted>" lap0 lap1)
+                   (setcdr rest (cddr rest))
+                   (setq lap (delq lap0 lap)))
+                  ((> net-pops 0)
+                   (byte-compile-log-lap
+                    "  %s %s\t-->\t<deleted> 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:
         ;;
@@ -2073,10 +2077,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 +2167,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 +2240,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 +2263,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))
         ;;
@@ -2351,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
@@ -2459,12 +2493,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 +2506,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,
@@ -2492,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
@@ -2530,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))
@@ -2547,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))
@@ -2563,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)
@@ -2652,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)))
diff --git a/lisp/emacs-lisp/lisp-mode.el b/lisp/emacs-lisp/lisp-mode.el
index bacc105a21..367f59e878 100644
--- a/lisp/emacs-lisp/lisp-mode.el
+++ b/lisp/emacs-lisp/lisp-mode.el
@@ -182,6 +182,7 @@ to a package-local <package>-loaddefs.el file.")
 ;; CL
 (put 'defconstant 'doc-string-elt 3)
 (put 'defparameter 'doc-string-elt 3)
+(put 'defstruct 'doc-string-elt 2)
 
 (defvar lisp-doc-string-elt-property 'doc-string-elt
   "The symbol property that holds the docstring position info.")
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index acbf206a3c..2439f1ed80 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -402,31 +402,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
@@ -437,11 +412,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)))
diff --git a/lisp/faces.el b/lisp/faces.el
index cc0b80ac45..7fe2cccba9 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -304,7 +304,16 @@ If the optional argument FRAME is given, report on face 
FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
 If FRAME is omitted or nil, use the selected frame."
   (let ((attrs
-        (delq :inherit (mapcar 'car face-attribute-name-alist)))
+         ;; The _value_ of :inherit teaches us nothing about how FACE
+         ;; looks compared to the default face.  Instead, we will ask
+         ;; `face-attribute' to take inheritance into account when
+         ;; examining other attributes.
+         (delq :inherit
+               ;; A difference in extension past EOL only matters when
+               ;; relevant attributes (such as :background) also
+               ;; differ from the default; otherwise this difference
+               ;; is a false positive.
+               (delq :extend (mapcar 'car face-attribute-name-alist))))
        (differs nil))
     (while (and attrs (not differs))
       (let* ((attr (pop attrs))
diff --git a/lisp/keymap.el b/lisp/keymap.el
index de90b03ba6..201a49cef8 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 <like-this>.  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-<left>\"    (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-<left>\"    (the function key named \"left\" with the hyper modifier)
   \"M-RET\"       (the \"return\" key with a meta modifier)
   \"C-M-<space>\" (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:
diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el
index c13b01aae5..8729cae4ba 100644
--- a/lisp/progmodes/c-ts-common.el
+++ b/lisp/progmodes/c-ts-common.el
@@ -194,7 +194,8 @@ comment."
       (when end-marker
         (goto-char end-marker)
         (delete-region (point) (+ end-len (point)))
-        (insert (make-string end-len ?\s))))))
+        (insert (make-string end-len ?\s)))
+      (goto-char orig-point))))
 
 (defun c-ts-common-comment-setup ()
   "Set up local variables for C-like comment.
@@ -280,7 +281,7 @@ special handling from our bracket-counting indent algorithm.
 
 This can be nil, meaning such special handling is not needed.")
 
-(defun c-ts-common-statement-offset (node parent &rest _)
+(defun c-ts-common-statement-offset (node parent bol &rest _)
   "This anchor is used for children of a statement inside a block.
 
 This function basically counts the number of block nodes (i.e.,
@@ -292,18 +293,21 @@ To support GNU style, on each block level, this function 
also
 checks whether the opening bracket { is on its own line, if so,
 it adds an extra level, except for the top-level.
 
-PARENT is NODE's parent."
+PARENT is NODE's parent, BOL is the beginning of non-whitespace
+characters on the current line."
   (let ((level 0))
+    ;; If NODE is a opening/closing bracket on its own line, take off
+    ;; one level because the code below assumes NODE is a statement
+    ;; _inside_ a {} block.
+    (when (and node
+               (or (string-match-p c-ts-common-indent-block-type-regexp
+                                   (treesit-node-type node))
+                   (save-excursion (goto-char bol) (looking-at-p "}"))))
+      (cl-decf level))
     ;; If point is on an empty line, NODE would be nil, but we pretend
     ;; there is a statement node.
     (when (null node)
       (setq node t))
-    ;; If NODE is a opening bracket on its own line, take off one
-    ;; level because the code below assumes NODE is a statement
-    ;; _inside_ a {} block.
-    (when (string-match-p c-ts-common-indent-block-type-regexp
-                          (treesit-node-type node))
-      (cl-decf level))
     ;; Go up the tree and compute indent level.
     (while (if (eq node t)
                (setq node parent)
@@ -321,9 +325,9 @@ PARENT is NODE's parent."
                                      (treesit-node-parent node))))
                    ;; Case (2).
                    (and parent-type
-                        (or (string-match-p
-                             c-ts-common-indent-block-type-regexp
-                             parent-type))))
+                        (string-match-p
+                         c-ts-common-indent-block-type-regexp
+                         parent-type)))
                  nil)
                 ;; Add a level.
                 ((looking-back (rx bol (* whitespace))
@@ -350,13 +354,6 @@ the bracket in the body."
         (1+ level)
       level)))
 
-(defun c-ts-mode--close-bracket-offset (node parent &rest _)
-  "Offset for the closing bracket, NODE.
-It's basically one level less that the statements in the block.
-PARENT is NODE's parent."
-  (- (c-ts-common-statement-offset node parent)
-     (symbol-value c-ts-common-indent-offset)))
-
 (provide 'c-ts-common)
 
 ;;; c-ts-common.el ends here
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 884fe6c3f1..586849e9a3 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -100,12 +100,11 @@ the value of SYM in `c-ts-mode' and `c++-ts-mode' buffers 
to VAL."
                   (setq-local treesit-simple-indent-rules
                               (treesit--indent-rules-optimize
                                (c-ts-mode--get-indent-style
-                                (if (eq major-mode 'c-ts-mode) 'c 'cpp))))))
+                                (if (derived-mode-p 'c-ts-mode) 'c 'cpp))))))
               res)
       (let ((buffer (car buffers)))
         (with-current-buffer buffer
-          ;; FIXME: Should we use `derived-mode-p' here?
-          (if (or (eq major-mode 'c-ts-mode) (eq major-mode 'c++-ts-mode))
+          (if (derived-mode-p 'c-ts-mode 'c++-ts-mode)
               (loop (append res (list buffer)) (cdr buffers))
             (loop res (cdr buffers))))))))
 
@@ -134,24 +133,33 @@ MODE is either `c' or `cpp'."
            (alist-get c-ts-mode-indent-style (c-ts-mode--indent-styles 
mode)))))
     `((,mode ,@style))))
 
-(defun c-ts-mode-set-style ()
-  "Set the indent style of C/C++ modes globally.
+(defun c-ts-mode--prompt-for-style ()
+  "Prompt for a indent style and return the symbol for it."
+  (let ((mode (if (derived-mode-p 'c-ts-mode) 'c 'c++)))
+    (intern
+     (completing-read
+      "Style: "
+      (mapcar #'car (c-ts-mode--indent-styles mode))
+      nil t nil nil "gnu"))))
+
+(defun c-ts-mode-set-style (style)
+  "Set the indent style of C/C++ modes globally to STYLE.
 
 This changes the current indent style of every C/C++ buffer and
 the default C/C++ indent style in this Emacs session."
-  (interactive)
-  ;; FIXME: Should we use `derived-mode-p' here?
-  (or (eq major-mode 'c-ts-mode) (eq major-mode 'c++-ts-mode)
-      (error "Buffer %s is not a c-ts-mode (c-ts-mode-set-style)"
-             (buffer-name)))
-  (c-ts-mode--indent-style-setter
-   'c-ts-mode-indent-style
-   ;; NOTE: We can probably use the interactive form for this.
-   (intern
-    (completing-read
-     "Select style: "
-     (mapcar #'car (c-ts-mode--indent-styles (if (eq major-mode 'c-ts-mode) 'c 
'cpp)))
-     nil t nil nil "gnu"))))
+  (interactive (list (c-ts-mode--prompt-for-style)))
+  (c-ts-mode--indent-style-setter 'c-ts-mode-indent-style style))
+
+(defun c-ts-mode-set-local-style (style)
+  "Set the C/C++ indent style of the current buffer to STYLE."
+  (interactive (list (c-ts-mode--prompt-for-style)))
+  (if (not (derived-mode-p 'c-ts-mode 'c++-ts-mode))
+      (user-error "The current buffer is not in `c-ts-mode' nor `c++-ts-mode'")
+    (setq-local c-ts-mode-indent-style style)
+    (setq treesit-simple-indent-rules
+          (treesit--indent-rules-optimize
+           (c-ts-mode--get-indent-style
+            (if (derived-mode-p 'c-ts-mode) 'c 'cpp))))))
 
 ;;; Syntax table
 
@@ -254,12 +262,16 @@ MODE is either `c' or `cpp'."
 
            ;; int[5] a = { 0, 0, 0, 0 };
            ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset)
+           ;; Statement in enum.
            ((parent-is "enumerator_list") point-min 
c-ts-common-statement-offset)
+           ;; Statement in struct and union.
            ((parent-is "field_declaration_list") point-min 
c-ts-common-statement-offset)
 
-           ;; {} blocks.
-           ((node-is "}") point-min c-ts-mode--close-bracket-offset)
+           ;; Statement in {} blocks.
            ((parent-is "compound_statement") point-min 
c-ts-common-statement-offset)
+           ;; Closing bracket.
+           ((node-is "}") point-min c-ts-common-statement-offset)
+           ;; Opening bracket.
            ((node-is "compound_statement") point-min 
c-ts-common-statement-offset)
 
            ,@(when (eq mode 'cpp)
@@ -824,6 +836,8 @@ in your configuration."
                 (c-ts-mode--get-indent-style 'c))
     ;; Font-lock.
     (setq-local treesit-font-lock-settings (c-ts-mode--font-lock-settings 'c))
+    ;; Navigation.
+    (setq-local treesit-defun-tactic 'top-level)
     (treesit-major-mode-setup)))
 
 ;;;###autoload
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index f1e93c1c23..86bc35baa7 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -10146,6 +10146,24 @@ This function might do hidden buffer changes."
        ;; This identifier is bound only in the inner let.
        '(setq start id-start))))
 
+(defmacro c-fdoc-assymetric-space-about-asterisk ()
+  ;; We've got a "*" at `id-start' between two identifiers, the first at
+  ;; `type-start'.  Return non-nil when there is either whitespace between the
+  ;; first id and the "*" or between the "*" and the second id, but not both.
+  `(let ((space-before-id
+        (save-excursion
+          (goto-char id-start)         ; Position of "*".
+          (and (> (skip-chars-forward "* \t\n\r") 0)
+               (memq (char-before) '(?\  ?\t ?\n ?\r)))))
+       (space-after-type
+        (save-excursion
+          (goto-char type-start)
+          (and (c-forward-type nil t)
+               (or (eolp)
+                   (memq (char-after) '(?\  ?\t)))))))
+     (not (eq (not space-before-id)
+             (not space-after-type)))))
+
 (defun c-forward-decl-or-cast-1 (preceding-token-end context last-cast-end
                                                     &optional inside-macro)
   ;; Move forward over a declaration or a cast if at the start of one.
@@ -11166,19 +11184,25 @@ This function might do hidden buffer changes."
               ;; CASE 16
               (when (and got-prefix-before-parens
                          at-type
-                         (or at-decl-end (looking-at "=[^=]"))
                          (memq context '(nil top))
                          (or (not got-suffix)
                              at-decl-start))
                 ;; Got something like "foo * bar;".  Since we're not inside
                 ;; an arglist it would be a meaningless expression because
                 ;; the result isn't used.  We therefore choose to recognize
-                ;; it as a declaration.  We only allow a suffix (which makes
-                ;; the construct look like a function call) when
-                ;; `at-decl-start' provides additional evidence that we do
-                ;; have a declaration.
+                ;; it as a declaration when there's "symmetrical WS" around
+                ;; the "*" or the flag `c-assymetry-fontification-flag' is
+                ;; not set.  We only allow a suffix (which makes the
+                ;; construct look like a function call) when `at-decl-start'
+                ;; provides additional evidence that we do have a
+                ;; declaration.
                 (setq maybe-expression t)
-                (throw 'at-decl-or-cast t))
+                (when (or (not c-asymmetry-fontification-flag)
+                          (looking-at "=[^=]")
+                          (c-fdoc-assymetric-space-about-asterisk))
+                  (when (eq at-type 'maybe)
+                    (setq unsafe-maybe t))
+                  (throw 'at-decl-or-cast t)))
 
               ;; CASE 17
               (when (and (or got-suffix-after-parens
@@ -11197,24 +11221,12 @@ This function might do hidden buffer changes."
                          got-prefix-before-parens
                          at-type
                          (or (not got-suffix)
-                             at-decl-start))
-                (let ((space-before-id
-                       (save-excursion
-                         (goto-char id-start) ; Position of "*".
-                         (and (> (skip-chars-forward "* \t\n\r") 0)
-                              (memq (char-before) '(?\  ?\t ?\n ?\r)))))
-                      (space-after-type
-                       (save-excursion
-                         (goto-char type-start)
-                         (and (c-forward-type nil t)
-                              (or (eolp)
-                                  (memq (char-after) '(?\  ?\t)))))))
-                  (when (not (eq (not space-before-id)
-                                 (not space-after-type)))
-                    (when (eq at-type 'maybe)
-                      (setq unsafe-maybe t))
-                    (setq maybe-expression t)
-                    (throw 'at-decl-or-cast t)))))
+                             at-decl-start)
+                         (c-fdoc-assymetric-space-about-asterisk))
+                (when (eq at-type 'maybe)
+                  (setq unsafe-maybe t))
+                (setq maybe-expression t)
+                (throw 'at-decl-or-cast t)))
 
           ;; CASE 18
           (when (and at-decl-end
diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el
index c160e6ad1d..b878986d7a 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 "{\\|<[^/>]*?" "}\\|</[^/>]*[^/]>" "<!--" mhtml-forward nil)
     ;; Add more support here.
     ))
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index 9fc0c360a2..beaab2e76e 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -209,9 +209,6 @@ values of OVERRIDE"
     (treesit-fontify-with-override (max plus-1 start) (min node-end end)
                                    font-lock-comment-face override)))
 
-(defun ruby-ts--builtin-method-p (node)
-  (string-match-p ruby-ts--builtin-methods (treesit-node-text node t)))
-
 (defun ruby-ts--font-lock-settings (language)
   "Tree-sitter font-lock settings for Ruby."
   (treesit-font-lock-rules
@@ -340,7 +337,7 @@ values of OVERRIDE"
    :language language
    :feature 'builtin-function
    `((((identifier) @font-lock-builtin-face)
-      (:pred ruby-ts--builtin-method-p @font-lock-builtin-face)))
+      (:match ,ruby-ts--builtin-methods @font-lock-builtin-face)))
 
    ;; Yuan recommends also putting method definitions into the
    ;; 'function' category (thus keeping it in both).  I've opted to
diff --git a/lisp/repeat.el b/lisp/repeat.el
index 0124ff4bc0..37d4aaec98 100644
--- a/lisp/repeat.el
+++ b/lisp/repeat.el
@@ -349,7 +349,7 @@ For example, you can set it to <return> 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,8 +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'.
-Used in `repeat-mode'."
+  "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))
@@ -612,7 +622,9 @@ Used in `repeat-mode'."
       (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/simple.el b/lisp/simple.el
index 7bda368d85..22aa043069 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -5871,6 +5871,25 @@ The value 0 disables blinking."
   :group 'killing
   :version "28.1")
 
+(defcustom copy-region-blink-predicate #'region-indistinguishable-p
+  "Whether the cursor must be blinked after a copy.
+When this condition holds, and the copied region fits in the
+current window, `kill-ring-save' will blink the cursor between
+point and mark for `copy-region-blink-delay' seconds."
+  :type '(radio (function-item region-indistinguishable-p)
+                (function-item :doc "Always blink point and mark." always)
+                (function-item :doc "Never blink point and mark." ignore)
+                (function :tag "Other predicate function"))
+  :group 'killing
+  :version "29.1")
+
+(defun region-indistinguishable-p ()
+  "Whether the current region is not denoted visually.
+This holds when the region is inactive, or when the `region' face
+cannot be distinguished from the `default' face."
+  (not (and (region-active-p)
+            (face-differs-from-default-p 'region))))
+
 (defun indicate-copied-region (&optional message-len)
   "Indicate that the region text has been copied interactively.
 If the mark is visible in the selected window, blink the cursor between
@@ -5891,8 +5910,7 @@ of this sample text; it defaults to 40."
        ;; was selected.  Don't do it if the region is highlighted.
        (when (and (numberp copy-region-blink-delay)
                   (> copy-region-blink-delay 0)
-                  (or (not (region-active-p))
-                      (not (face-background 'region nil t))))
+                  (funcall copy-region-blink-predicate))
          ;; Swap point and mark.
          (set-marker (mark-marker) (point) (current-buffer))
          (goto-char mark)
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 9f53b649ef..7c3069ca26 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -2653,14 +2653,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 0cd30822ff..2d9f746d8f 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:
diff --git a/src/insdel.c b/src/insdel.c
index 0e1e98664b..e459d0cfa1 100644
--- a/src/insdel.c
+++ b/src/insdel.c
@@ -1101,6 +1101,10 @@ insert_from_gap_1 (ptrdiff_t nchars, ptrdiff_t nbytes, 
bool text_at_gap_tail)
   eassert (NILP (BVAR (current_buffer, enable_multibyte_characters))
            ? nchars == nbytes : nchars <= nbytes);
 
+#ifdef HAVE_TREE_SITTER
+  ptrdiff_t ins_bytepos = GPT_BYTE;
+#endif
+
   GAP_SIZE -= nbytes;
   if (! text_at_gap_tail)
     {
@@ -1115,6 +1119,12 @@ insert_from_gap_1 (ptrdiff_t nchars, ptrdiff_t nbytes, 
bool text_at_gap_tail)
   /* Put an anchor to ensure multi-byte form ends at gap.  */
   if (GAP_SIZE > 0) *(GPT_ADDR) = 0;
   eassert (GPT <= GPT_BYTE);
+
+#ifdef HAVE_TREE_SITTER
+  eassert (nbytes >= 0);
+  eassert (ins_bytepos >= 0);
+  treesit_record_change (ins_bytepos, ins_bytepos, ins_bytepos + nbytes);
+#endif
 }
 
 /* Insert a sequence of NCHARS chars which occupy NBYTES bytes
@@ -1150,12 +1160,6 @@ insert_from_gap (ptrdiff_t nchars, ptrdiff_t nbytes, 
bool text_at_gap_tail)
                                   current_buffer, 0);
     }
 
-#ifdef HAVE_TREE_SITTER
-  eassert (nbytes >= 0);
-  eassert (ins_bytepos >= 0);
-  treesit_record_change (ins_bytepos, ins_bytepos, ins_bytepos + nbytes);
-#endif
-
   if (ins_charpos < PT)
     adjust_point (nchars, nbytes);
 
@@ -1191,6 +1195,9 @@ insert_from_buffer (struct buffer *buf,
 #endif
 }
 
+/* NOTE: If we ever make insert_from_buffer_1 public, make sure to
+   move the call to treesit_record_change into it.  */
+
 static void
 insert_from_buffer_1 (struct buffer *buf,
                      ptrdiff_t from, ptrdiff_t nchars, bool inherit)
diff --git a/src/lisp.h b/src/lisp.h
index 6fda1e9550..b545c49817 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4807,6 +4807,9 @@ extern ptrdiff_t find_newline_no_quit (ptrdiff_t, 
ptrdiff_t,
                                       ptrdiff_t, ptrdiff_t *);
 extern ptrdiff_t find_before_next_newline (ptrdiff_t, ptrdiff_t,
                                           ptrdiff_t, ptrdiff_t *);
+extern EMACS_INT search_buffer (Lisp_Object, ptrdiff_t, ptrdiff_t,
+                               ptrdiff_t, ptrdiff_t, EMACS_INT,
+                               int, Lisp_Object, Lisp_Object, bool);
 extern void syms_of_search (void);
 extern void clear_regexp_cache (void);
 
diff --git a/src/search.c b/src/search.c
index dbc5a83946..0bb52c03ee 100644
--- a/src/search.c
+++ b/src/search.c
@@ -68,9 +68,6 @@ static EMACS_INT simple_search (EMACS_INT, unsigned char *, 
ptrdiff_t,
 static EMACS_INT boyer_moore (EMACS_INT, unsigned char *, ptrdiff_t,
                               Lisp_Object, Lisp_Object, ptrdiff_t,
                               ptrdiff_t, int);
-static EMACS_INT search_buffer (Lisp_Object, ptrdiff_t, ptrdiff_t,
-                                ptrdiff_t, ptrdiff_t, EMACS_INT, int,
-                                Lisp_Object, Lisp_Object, bool);
 
 Lisp_Object re_match_object;
 
@@ -1510,7 +1507,7 @@ search_buffer_non_re (Lisp_Object string, ptrdiff_t pos,
   return result;
 }
 
-static EMACS_INT
+EMACS_INT
 search_buffer (Lisp_Object string, ptrdiff_t pos, ptrdiff_t pos_byte,
               ptrdiff_t lim, ptrdiff_t lim_byte, EMACS_INT n,
               int RE, Lisp_Object trt, Lisp_Object inverse_trt, bool posix)
diff --git a/src/sqlite.c b/src/sqlite.c
index c96841e63f..0361514766 100644
--- a/src/sqlite.c
+++ b/src/sqlite.c
@@ -399,7 +399,7 @@ row_to_value (sqlite3_stmt *stmt)
   int len = sqlite3_column_count (stmt);
   Lisp_Object values = Qnil;
 
-  for (int i = 0; i < len; ++i)
+  for (int i = len - 1; i >= 0; i--)
     {
       Lisp_Object v = Qnil;
 
@@ -434,7 +434,7 @@ row_to_value (sqlite3_stmt *stmt)
       values = Fcons (v, values);
     }
 
-  return Fnreverse (values);
+  return values;
 }
 
 static Lisp_Object
@@ -718,11 +718,15 @@ Only modules on Emacs' list of allowed modules can be 
loaded.  */)
 #endif /* HAVE_SQLITE3_LOAD_EXTENSION */
 
 DEFUN ("sqlite-next", Fsqlite_next, Ssqlite_next, 1, 1, 0,
-       doc: /* Return the next result set from SET.  */)
+       doc: /* Return the next result set from SET.
+Return nil when the statement has finished executing successfully.  */)
   (Lisp_Object set)
 {
   check_sqlite (set, true);
 
+  if (XSQLITE (set)->eof)
+    return Qnil;
+
   int ret = sqlite3_step (XSQLITE (set)->stmt);
   if (ret != SQLITE_ROW && ret != SQLITE_OK && ret != SQLITE_DONE)
     xsignal1 (Qsqlite_error, build_string (sqlite3_errmsg (XSQLITE 
(set)->db)));
diff --git a/src/treesit.c b/src/treesit.c
index b163685419..8e772523cc 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -72,6 +72,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #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
@@ -2466,13 +2470,42 @@ treesit_predicate_match (Lisp_Object args, struct 
capture_range captures)
              build_string ("The second argument to `match' should "
                            "be a capture name, not a string"));
 
-  Lisp_Object text = treesit_predicate_capture_name_to_text (capture_name,
+  Lisp_Object node = treesit_predicate_capture_name_to_node (capture_name,
                                                             captures);
 
-  if (fast_string_match (regexp, text) >= 0)
-    return true;
-  else
-    return false;
+  struct buffer *old_buffer = current_buffer;
+  struct buffer *buffer = XBUFFER (XTS_PARSER (XTS_NODE 
(node)->parser)->buffer);
+  set_buffer_internal (buffer);
+
+  TSNode treesit_node = XTS_NODE (node)->node;
+  ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
+  uint32_t start_byte_offset = ts_node_start_byte (treesit_node);
+  uint32_t end_byte_offset = ts_node_end_byte (treesit_node);
+  ptrdiff_t start_byte = visible_beg + start_byte_offset;
+  ptrdiff_t end_byte = visible_beg + end_byte_offset;
+  ptrdiff_t start_pos = BYTE_TO_CHAR (start_byte);
+  ptrdiff_t end_pos = BYTE_TO_CHAR (end_byte);
+  ptrdiff_t old_begv = BEGV;
+  ptrdiff_t old_begv_byte = BEGV_BYTE;
+  ptrdiff_t old_zv = ZV;
+  ptrdiff_t old_zv_byte = ZV_BYTE;
+
+  BEGV = start_pos;
+  BEGV_BYTE = start_byte;
+  ZV = end_pos;
+  ZV_BYTE = end_byte;
+
+  ptrdiff_t val = search_buffer (regexp, start_pos, start_byte,
+                                end_pos, end_byte, 1, 1, Qnil, Qnil, false);
+
+  BEGV = old_begv;
+  BEGV_BYTE = old_begv_byte;
+  ZV = old_zv;
+  ZV_BYTE = old_zv_byte;
+
+  set_buffer_internal (old_buffer);
+
+  return (val > 0);
 }
 
 /* Handles predicate (#pred FN ARG...).  Return true if FN returns
diff --git a/src/xfaces.c b/src/xfaces.c
index d6ffc92d20..4207b73ee2 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -2817,8 +2817,7 @@ merge_face_ref (struct window *w,
              else if (EQ (keyword, QCstipple))
                {
 #if defined (HAVE_WINDOW_SYSTEM)
-                 Lisp_Object pixmap_p = Fbitmap_spec_p (value);
-                 if (!NILP (pixmap_p))
+                 if (NILP (value) || !NILP (Fbitmap_spec_p (value)))
                    to[LFACE_STIPPLE_INDEX] = value;
                  else
                    err = true;
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
index 07698077ff..ba4f854baf 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
@@ -1,9 +1,9 @@
 Code:
   (lambda ()
-    (setq indent-tabs-mode nil)
-    (setq c-ts-mode-indent-offset 2)
-    (setq c-ts-mode-indent-style 'bsd)
     (c-ts-mode)
+    (setq-local indent-tabs-mode nil)
+    (setq-local c-ts-mode-indent-offset 2)
+    (c-ts-mode-set-local-style 'bsd)
     (indent-region (point-min) (point-max)))
 
 Point-Char: |
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index 0ecbf922b1..058c6e9099 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -1,9 +1,9 @@
 Code:
   (lambda ()
-    (setq indent-tabs-mode nil)
-    (setq c-ts-mode-indent-offset 2)
-    (setq c-ts-mode-indent-style 'gnu)
     (c-ts-mode)
+    (setq-local indent-tabs-mode nil)
+    (setq-local c-ts-mode-indent-offset 2)
+    (c-ts-mode-set-local-style 'gnu)
     (indent-region (point-min) (point-max)))
 
 Point-Char: |
@@ -135,32 +135,6 @@ int main() {
 }
 =-=-=
 
-Name: Bracket-less Block-Statement (Linux Style) (bug#61026)
-
-=-=-=
-int main() {
-  while (true)
-    if (true) {
-      puts ("Hello");
-    }
-  for (int i=0;
-       i<5;
-       i++)
-    if (true) {
-      puts ("Hello");
-    }
-  do
-    if (true) {
-      puts ("Hello");
-    }
-  while (true);
-  if (true)
-    if (true) {
-      puts ("Hello");
-    }
-}
-=-=-=
-
 Name: Multiline Parameter List (bug#60398)
 
 =-=
@@ -219,10 +193,10 @@ line 2
 
 Code:
   (lambda ()
-    (setq indent-tabs-mode nil)
-    (setq c-ts-mode-indent-offset 8)
-    (setq c-ts-mode-indent-style 'linux)
     (c-ts-mode)
+    (setq-local indent-tabs-mode nil)
+    (setq-local c-ts-mode-indent-offset 8)
+    (c-ts-mode-set-local-style 'linux)
     (indent-region (point-min) (point-max)))
 
 Name: Labels (Linux Style)
@@ -244,3 +218,29 @@ label:
         }
 }
 =-=-=
+
+Name: Bracket-less Block-Statement (Linux Style) (bug#61026)
+
+=-=-=
+int main() {
+  while (true)
+    if (true) {
+      puts ("Hello");
+    }
+  for (int i=0;
+       i<5;
+       i++)
+    if (true) {
+      puts ("Hello");
+    }
+  do
+    if (true) {
+      puts ("Hello");
+    }
+  while (true);
+  if (true)
+    if (true) {
+      puts ("Hello");
+    }
+}
+=-=-=



reply via email to

[Prev in Thread] Current Thread [Next in Thread]