emacs-diffs
[Top][All Lists]
Advanced

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

feature/android f99f759931 2/2: Merge remote-tracking branch 'origin/mas


From: Po Lu
Subject: feature/android f99f759931 2/2: Merge remote-tracking branch 'origin/master' into feature/android
Date: Thu, 19 Jan 2023 09:20:43 -0500 (EST)

branch: feature/android
commit f99f7599315bb11531d49fc6483f4d64242f6903
Merge: a496509ced 9161a302c9
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Merge remote-tracking branch 'origin/master' into feature/android
---
 doc/emacs/maintaining.texi                         |   9 +-
 doc/emacs/modes.texi                               |  13 +-
 doc/lispref/minibuf.texi                           |   2 +-
 doc/lispref/strings.texi                           |   4 +-
 doc/misc/eshell.texi                               | 136 ++++++++++++-----
 etc/NEWS.29                                        |   9 +-
 lisp/emacs-lisp/bytecomp.el                        |  12 +-
 lisp/emacs-lisp/cl-macs.el                         |   2 +-
 lisp/emacs-lisp/macroexp.el                        |  13 +-
 lisp/emacs-lisp/warnings.el                        |   8 +-
 lisp/erc/erc-common.el                             |  13 +-
 lisp/erc/erc-compat.el                             |   4 +-
 lisp/erc/erc.el                                    |  26 +++-
 lisp/eshell/em-basic.el                            |   3 +-
 lisp/eshell/esh-var.el                             |   7 +-
 lisp/files.el                                      |  20 ++-
 lisp/net/ange-ftp.el                               |   7 +
 lisp/net/tramp-archive.el                          |  13 +-
 lisp/net/tramp-crypt.el                            |   2 +-
 lisp/progmodes/c-ts-mode.el                        |  44 ++++++
 lisp/progmodes/cc-defs.el                          |  22 +++
 lisp/progmodes/cc-engine.el                        |  40 +++--
 lisp/progmodes/cc-fonts.el                         |  66 +++++++--
 lisp/progmodes/cc-mode.el                          |  40 ++++-
 lisp/progmodes/ruby-ts-mode.el                     | 162 ++++++++++++---------
 lisp/replace.el                                    |   6 +-
 lisp/treesit.el                                    |  34 +++--
 lisp/vc/vc-dir.el                                  |   8 +-
 lisp/window.el                                     |  12 +-
 src/buffer.c                                       |  10 +-
 src/treesit.c                                      |  66 ++++++---
 src/xterm.c                                        |   2 +
 test/lisp/erc/erc-scenarios-base-local-modules.el  | 100 ++++++++++++-
 test/lisp/erc/erc-tests.el                         |  41 ++++--
 .../resources/base/netid/bouncer/barnet-again.eld  |  10 +-
 .../resources/base/netid/bouncer/foonet-again.eld  |  10 +-
 test/lisp/eshell/em-prompt-tests.el                |   6 +-
 test/lisp/net/tramp-archive-tests.el               |  15 +-
 test/lisp/net/tramp-tests.el                       |  67 ++++++---
 test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb |  94 ++++++++++++
 test/lisp/progmodes/ruby-ts-mode-tests.el          |   6 +-
 test/src/buffer-tests.el                           |  46 +++---
 42 files changed, 906 insertions(+), 304 deletions(-)

diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 8c77ded55d..5191bb2918 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -1331,11 +1331,18 @@ point is on a directory entry, mark all files in that 
directory tree
 listed files and directories.
 
 @findex vc-dir-mark-by-regexp
-@item %
+@item % m
+@itemx * %
 You can use this command to mark files by regexp
 (@code{vc-dir-mark-by-regexp}).  If given a prefix, unmark files
 instead.
 
+@findex vc-dir-mark-registered-files
+@item * r
+You can use this command to mark files that are in one of registered
+states, including edited, added or removed.
+(@code{vc-dir-mark-registered-files}).
+
 @item G
 Add the file under point to the list of files that the VC should
 ignore (@code{vc-dir-ignore}).  For instance, if the VC is Git, it
diff --git a/doc/emacs/modes.texi b/doc/emacs/modes.texi
index d0eacce084..06f9929092 100644
--- a/doc/emacs/modes.texi
+++ b/doc/emacs/modes.texi
@@ -430,10 +430,15 @@ For example, one element normally found in the list has 
the form
 mode for files whose names end in @file{.c}.  (Note that @samp{\\} is
 needed in Lisp syntax to include a @samp{\} in the string, which must
 be used to suppress the special meaning of @samp{.} in regexps.)  If
-the element has the form @code{(@var{regexp} @var{mode-function}
-@var{flag})} and @var{flag} is non-@code{nil}, then after calling
-@var{mode-function}, Emacs discards the suffix that matched
-@var{regexp} and searches the list again for another match.
+the element has the form @w{@code{(@var{regexp} @var{mode-function}
+@var{flag})}} and @var{flag} is non-@code{nil}, then after calling
+@var{mode-function} (if it is non-@code{nil}), Emacs discards the
+suffix that matched @var{regexp} and searches the list again for
+another match.  This ``recursive extension stripping'' is used for
+files which have multiple extensions, and the ``outer'' extension
+hides the ``inner'' one that actually specifies the right mode.  For
+example, backup files and GPG-encrypted files with @file{.gpg}
+extension use this feature.
 
 @vindex auto-mode-case-fold
   On GNU/Linux and other systems with case-sensitive file names, Emacs
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index 18125c372c..114e5d38a8 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -312,7 +312,7 @@ to @code{regexp-history}.
 
 @cindex @code{case-fold}, text property
 @findex read-regexp-case-fold-search
-The user can use the @kbd{M-c} command to indicate whether case
+The user can use the @kbd{M-s c} command to indicate whether case
 folding should be on or off.  If the user has used this command, the
 returned string will have the text property @code{case-fold} set to
 either @code{fold} or @code{inhibit-fold}.  It is up to the caller of
diff --git a/doc/lispref/strings.texi b/doc/lispref/strings.texi
index ca18f0a9cc..3d86a87516 100644
--- a/doc/lispref/strings.texi
+++ b/doc/lispref/strings.texi
@@ -911,8 +911,8 @@ This function returns a new string containing one character,
 @end defun
 
 @defun string-to-char string
-  This function returns the first character in @var{string}.  This
-mostly identical to @code{(aref string 0)}, except that it returns 0
+  This function returns the first character in @var{string}.  This is
+mostly identical to @w{@code{(aref string 0)}}, except that it returns 0
 if the string is empty.  (The value is also 0 when the first character
 of @var{string} is the null character, @acronym{ASCII} code 0.)  This
 function may be eliminated in the future if it does not seem useful
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index c40ff58f42..57a2020fdc 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -64,10 +64,11 @@ modify this GNU manual.''
 
 Eshell is a shell-like command interpreter implemented in Emacs Lisp.
 It invokes no external processes except for those requested by the
-user.  It is intended to be an alternative to the IELM (@pxref{Lisp 
Interaction, Emacs Lisp Interaction, , emacs, The Emacs Editor})
-REPL for Emacs @emph{and} with an interface similar to command shells
-such as @command{bash}, @command{zsh}, @command{rc}, or
-@command{4dos}.
+user.  It is intended to be an alternative to the IELM (@pxref{Lisp
+Interaction, Emacs Lisp Interaction, , emacs, The Emacs Editor})
+REPL@footnote{Short for ``Read-Eval-Print Loop''.} for Emacs
+@emph{and} with an interface similar to command shells such as
+@command{bash}, @command{zsh}, @command{rc}, or @command{4dos}.
 @c This manual is updated to release 2.4 of Eshell.
 
 @insertcopying
@@ -193,6 +194,13 @@ In a command shell, everything is done by invoking 
commands.  This
 chapter covers command invocations in Eshell, including the command
 history and invoking commands in a script file.
 
+Unlike regular system shells, Eshell never invokes kernel functions
+directly, such as @code{exec(3)}.  Instead, it uses the Lisp functions
+available in the Emacs Lisp library.  It does this by transforming the
+input line into a callable Lisp form.@footnote{To see the Lisp form
+that will be invoked, type this as the Eshell prompt:
+@kbd{eshell-parse-command 'echo hello'}}
+
 @menu
 * Invocation::
 * Arguments::
@@ -207,23 +215,16 @@ history and invoking commands in a script file.
 
 @node Invocation
 @section Invocation
-Unlike regular system shells, Eshell never invokes kernel functions
-directly, such as @code{exec(3)}.  Instead, it uses the Lisp functions
-available in the Emacs Lisp library.  It does this by transforming the
-input line into a callable Lisp form.@footnote{To see the Lisp form that will 
be invoked, type: @samp{eshell-parse-command "echo hello"}}
+Eshell is both a command shell and an Emacs Lisp @acronym{REPL}.  As a
+result, you can invoke commands in two different ways: in @dfn{command
+form} or in @dfn{lisp form}.
 
-The command can be either an Elisp function or an external command.
-Eshell looks first for an alias (@pxref{Aliases}) with the same name as the
-command, then a built-in (@pxref{Built-ins}) or a function with the
-same name; if there is no match, it then tries to execute it as an
-external command.
-
-The semicolon (@code{;}) can be used to separate multiple command
-invocations on a single line.  You can also separate commands with
-@code{&&} or @code{||}. When using @code{&&}, Eshell will execute the
-second command only if the first succeeds (i.e.@: has an exit
-status of 0); with @code{||}, Eshell will execute the second command
-only if the first fails.
+You can use the semicolon (@code{;}) to separate multiple command
+invocations on a single line, executing each in turn.  You can also
+separate commands with @code{&&} or @code{||}. When using @code{&&},
+Eshell will execute the second command only if the first succeeds
+(i.e.@: has an exit status of 0); with @code{||}, Eshell will execute
+the second command only if the first fails.
 
 A command invocation followed by an ampersand (@code{&}) will be run
 in the background.  Eshell has no job control, so you can not suspend
@@ -232,12 +233,80 @@ the foreground.  That said, background processes invoked 
from Eshell
 can be controlled the same way as any other background process in
 Emacs.
 
+@subsection Command form
+Command form looks much the same as in other shells.  A command
+consists of arguments separated by spaces; the first argument is the
+command to run, with any subsequent arguments being passed to that
+command.
+
+@example
+~ $ echo hello
+hello
+@end example
+
+@cindex order of looking for commands
+@cindex command lookup order
+The command can be either an Elisp function or an external command.
+Eshell looks for the command in the following order:
+
+@enumerate
+@item
+As a command alias (@pxref{Aliases})
+
+@item
+As a built-in command (@pxref{Built-ins})
+
+@item
+As an external program
+
+@item
+As an ordinary Lisp function
+@end enumerate
+
+@vindex eshell-prefer-lisp-functions
+If you would prefer to use ordinary Lisp functions over external
+programs, set the option @code{eshell-prefer-lisp-functions} to
+@code{t}.  This will swap the lookup order of the last two items.
+
+You can also group command forms together into a subcommand with curly
+braces (@code{@{@}}).  This lets you use the output of a subcommand as
+an argument to another command, or within control flow statements
+(@pxref{Control Flow}).
+
+@example
+~ $ echo @{echo hello; echo there@}
+hellothere
+@end example
+
+@subsection Lisp form
+Lisp form looks like ordinary Emacs Lisp code, because that's what it
+is.  As a result, you can use any syntax normally available to an
+Emacs Lisp program (@pxref{Top, , , elisp, The Emacs Lisp Reference
+Manual}).
+
+@example
+~ $ (format "hello, %s" user-login-name)
+hello, user
+@end example
+
+In addition, you can @emph{combine} command forms and Lisp forms
+together into single statements, letting you use whatever form is the
+most convenient for expressing your intentions.
+
+@example
+~ $ ls *.patch > (format-time-string "%F.log")
+@end example
+
+This command writes a list of all files matching the glob pattern
+@code{*.patch} (@pxref{Globbing}) to a file named
+@code{@var{current-date}.log} (@pxref{Redirection}).
+
 @node Arguments
 @section Arguments
-Ordinarily, command arguments are parsed by Eshell as either strings
+Ordinarily, Eshell parses arguments in command form as either strings
 or numbers, depending on what the parser thinks they look like.  To
-specify an argument of some other data type, you can use an
-@ref{Dollars Expansion, Elisp expression}:
+specify an argument of some other data type, you can use a Lisp form
+(@pxref{Invocation}):
 
 @example
 ~ $ echo (list 1 2 3)
@@ -354,10 +423,6 @@ eshell/sudo is a compiled Lisp function in `em-tramp.el'.
 sudo is an alias, defined as "*sudo $@@*"
 @end example
 
-@vindex eshell-prefer-lisp-functions
-If you would prefer to use the built-in commands instead of the external
-commands, set @code{eshell-prefer-lisp-functions} to @code{t}.
-
 Some of the built-in commands have different behavior from their
 external counterparts, and some have no external counterpart.  Most of
 these will print a usage message when given the @code{--help} option.
@@ -923,15 +988,14 @@ For example, you could handle a subset of the options for 
the
 @node Variables
 @section Variables
 @vindex eshell-prefer-lisp-variables
-Since Eshell is a combination of an Emacs @acronym{REPL}@footnote{
-Short for ``Read-Eval-Print Loop''.
-} and a command shell, it can refer to variables from two different
-sources: ordinary Emacs Lisp variables, as well as environment
-variables.  By default, when using a variable in Eshell, it will first
-look in the list of built-in variables, then in the list of
-environment variables, and finally in the list of Lisp variables.  If
-you would prefer to use Lisp variables over environment variables, you
-can set @code{eshell-prefer-lisp-variables} to @code{t}.
+Since Eshell is a combination of an Emacs @acronym{REPL} and a command
+shell, it can refer to variables from two different sources: ordinary
+Emacs Lisp variables, as well as environment variables.  By default,
+when using a variable in Eshell, it will first look in the list of
+built-in variables, then in the list of environment variables, and
+finally in the list of Lisp variables.  If you would prefer to use
+Lisp variables over environment variables, you can set
+@code{eshell-prefer-lisp-variables} to @code{t}.
 
 You can set variables in a few different ways.  To set a Lisp
 variable, you can use the command @samp{setq @var{name} @var{value}},
diff --git a/etc/NEWS.29 b/etc/NEWS.29
index d1ddd0194c..9f735bec44 100644
--- a/etc/NEWS.29
+++ b/etc/NEWS.29
@@ -2079,7 +2079,7 @@ The VC Directory buffer now uses the prefix 'b' for these 
branch-related
 commands.
 
 +++
-*** New command '%' ('vc-dir-mark-by-regexp').
+*** New command 'vc-dir-mark-by-regexp' bound to '% m' and '* %'.
 This command marks files based on a regexp.  If given a prefix
 argument, unmark instead.
 
@@ -3235,6 +3235,11 @@ programs in the C language.
 An optional major mode based on the tree-sitter library for editing
 programs in the C++ language.
 
++++
+*** New command 'c-or-c++-ts-mode'.
+A command that automatically guesses the language of a header file,
+and enables either 'c-ts-mode' or 'c++-ts-mode' accordingly.
+
 +++
 *** New major mode 'java-ts-mode'.
 An optional major mode based on the tree-sitter library for editing
@@ -3802,7 +3807,7 @@ These function now take an optional comparison PREDICATE 
argument.
 ** 'read-multiple-choice' can now use long-form answers.
 
 +++
-** 'M-c' in 'read-regexp' now toggles case folding.
+** 'M-s c' in 'read-regexp' now toggles case folding.
 
 +++
 ** 'completing-read' now allows a function as its REQUIRE-MATCH argument.
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index fb4b73b1c1..aa9521e5a6 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -1772,10 +1772,16 @@ It is too wide if it has any lines longer than the 
largest of
            kind name col))
         ;; There's a "naked" ' character before a symbol/list, so it
         ;; should probably be quoted with \=.
-        (when (string-match-p "\\( [\"#]\\|[ \t]\\|^\\)'[a-z(]" docs)
+        (when (string-match-p (rx (| (in " \t") bol)
+                                  (? (in "\"#"))
+                                  "'"
+                                  (in "A-Za-z" "("))
+                              docs)
           (byte-compile-warn-x
-           name "%s%sdocstring has wrong usage of unescaped single quotes (use 
\\= or different quoting)"
-           kind name))
+           name
+           (concat "%s%sdocstring has wrong usage of unescaped single quotes"
+                   " (use \\=%c or different quoting such as %c...%c)")
+           kind name ?' ?` ?'))
         ;; There's a "Unicode quote" in the string -- it should probably
         ;; be an ASCII one instead.
         (when (byte-compile-warning-enabled-p 'docstrings-non-ascii-quotes)
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 36aab087d9..cffe8b09f5 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -2811,7 +2811,7 @@ values.  Note that this macro is *not* available in 
Common Lisp.
 As a special case, if `(PLACE)' is used instead of `(PLACE VALUE)',
 the PLACE is not modified before executing BODY.
 
-See info node `(cl) Function Bindings' for details.
+See info node `(cl) Modify Macros' for details.
 
 \(fn ((PLACE VALUE) ...) BODY...)"
   (declare (indent 1) (debug ((&rest [&or (symbolp form)
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index 069adb3eda..c909ffb693 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -458,12 +458,13 @@ Assumes the caller has bound 
`macroexpand-all-environment'."
                  (let ((arg (nth funarg form)))
                    (when (and (eq 'quote (car-safe arg))
                               (eq 'lambda (car-safe (cadr arg))))
-                     (setcar (nthcdr funarg form)
-                             (macroexp-warn-and-return
-                              (format "%S quoted with ' rather than with #'"
-                                      (let ((f (cadr arg)))
-                                        (if (symbolp f) f `(lambda ,(nth 1 f) 
...))))
-                              arg nil nil (cadr arg))))))
+                     (setcar
+                      (nthcdr funarg form)
+                      (macroexp-warn-and-return
+                       (format
+                        "(lambda %s ...) quoted with ' rather than with #'"
+                        (or (nth 1 (cadr arg)) "()"))
+                       arg nil nil (cadr arg))))))
                ;; Macro expand compiler macros.  This cannot be delayed to
                ;; byte-optimize-form because the output of the compiler-macro 
can
                ;; use macros.
diff --git a/lisp/emacs-lisp/warnings.el b/lisp/emacs-lisp/warnings.el
index 9505c93581..31b840d6c8 100644
--- a/lisp/emacs-lisp/warnings.el
+++ b/lisp/emacs-lisp/warnings.el
@@ -204,8 +204,12 @@ SUPPRESS-LIST is the list of kinds of warnings to 
suppress."
     some-match))
 
 (define-icon warnings-suppress button
-  '((emoji "⛔")
-    (symbol " ■ ")
+  `((emoji "⛔")
+    ;; Many MS-Windows console fonts don't have good glyphs for U+25A0.
+    (symbol ,(if (and (eq system-type 'windows-nt)
+                      (null window-system))
+                 " » "
+               " ■ "))
     (text " stop "))
   "Suppress warnings."
   :version "29.1"
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 9eb4f1a900..994555acec 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -202,12 +202,13 @@ if ARG is omitted or nil.
            (,disable)))
        ,(erc--assemble-toggle local-p name enable mode t enable-body)
        ,(erc--assemble-toggle local-p name disable mode nil disable-body)
-       ,(when (and alias (not (eq name alias)))
-          `(defalias
-             ',(intern
-                (format "erc-%s-mode"
-                        (downcase (symbol-name alias))))
-             #',mode))
+       ,@(and-let* ((alias)
+                    ((not (eq name alias)))
+                    (aname (intern (format "erc-%s-mode"
+                                           (downcase (symbol-name alias))))))
+           `((defalias ',aname #',mode)
+             (put ',aname 'erc-module ',(erc--normalize-module-symbol name))))
+       (put ',mode 'erc-module ',(erc--normalize-module-symbol name))
        ;; For find-function and find-variable.
        (put ',mode    'definition-name ',name)
        (put ',enable  'definition-name ',name)
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index 73ce612a33..5601ede27a 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -260,8 +260,8 @@ If START or END is negative, it counts from the end."
           (dolist (e rv out)
             (when-let* ((s (plist-get e :secret))
                         (v (auth-source--obfuscate s)))
-              (setf (plist-get e :secret)
-                    (apply-partially #'auth-source--deobfuscate v)))
+              (setq e (plist-put e :secret (apply-partially
+                                            #'auth-source--deobfuscate v))))
             (push e out)))
       rv)))
 
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index ba7db15cf8..7f51b7bfb2 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -1305,6 +1305,14 @@ See also `erc-show-my-nick'."
 
 (defvar-local erc-dbuf nil)
 
+;; See comments in `erc-scenarios-base-local-modules' explaining why
+;; this is insufficient as a public interface.
+
+(defvar erc--target-priors nil
+  "Analogous to `erc--server-reconnecting' but for target buffers.
+Bound to local variables from an existing (logical) session's
+buffer during local-module setup and `erc-mode-hook' activation.")
+
 (defun erc--target-from-string (string)
   "Construct an `erc--target' variant from STRING."
   (funcall (if (erc-channel-p string)
@@ -1950,7 +1958,8 @@ nil."
       (let ((out (list (reverse new-modes))))
         (pcase-dolist (`(,k . ,v) old-vars)
           (when (and (string-prefix-p "erc-" (symbol-name k))
-                     (string-suffix-p "-mode" (symbol-name k)))
+                     (string-suffix-p "-mode" (symbol-name k))
+                     (get k 'erc-module))
             (if v
                 (cl-pushnew k (car out))
               (setf (car out) (delq k (car out)))
@@ -1985,7 +1994,9 @@ Returns the buffer for the given server or channel."
   (let* ((target (and channel (erc--target-from-string channel)))
          (buffer (erc-get-buffer-create server port nil target id))
          (old-buffer (current-buffer))
-         (old-vars (and target (buffer-local-variables)))
+         (erc--target-priors (and target ; buf from prior session
+                                  (buffer-local-value 'erc--target buffer)
+                                  (buffer-local-variables buffer)))
          (old-recon-count erc-server-reconnect-count)
          (old-point nil)
          (delayed-modules nil)
@@ -1998,7 +2009,8 @@ Returns the buffer for the given server or channel."
     (setq old-point (point))
     (setq delayed-modules
           (erc--merge-local-modes (erc--update-modules)
-                                  (or erc--server-reconnecting old-vars)))
+                                  (or erc--server-reconnecting
+                                      erc--target-priors)))
 
     (delay-mode-hooks (erc-mode))
 
@@ -2071,9 +2083,7 @@ Returns the buffer for the given server or channel."
 
     (erc-determine-parameters server port nick full-name user passwd)
 
-    (save-excursion (run-mode-hooks))
-    (dolist (mod (car delayed-modules)) (funcall mod +1))
-    (dolist (var (cdr delayed-modules)) (set var nil))
+    ;; FIXME consolidate this prompt-setup logic with the pass above.
 
     ;; set up prompt
     (unless continued-session
@@ -2086,6 +2096,10 @@ Returns the buffer for the given server or channel."
       (erc-display-prompt)
       (goto-char (point-max)))
 
+    (save-excursion (run-mode-hooks)
+                    (dolist (mod (car delayed-modules)) (funcall mod +1))
+                    (dolist (var (cdr delayed-modules)) (set var nil)))
+
     ;; Saving log file on exit
     (run-hook-with-args 'erc-connect-pre-hook buffer)
 
diff --git a/lisp/eshell/em-basic.el b/lisp/eshell/em-basic.el
index dfbe4db089..bfff3bdf56 100644
--- a/lisp/eshell/em-basic.el
+++ b/lisp/eshell/em-basic.el
@@ -132,7 +132,8 @@ or `eshell-printn' for display."
      ;; bug#27361.
      (when (equal output-newline '(nil))
        (display-warning
-        :warning "To terminate with a newline, you should use -N instead."))
+        '(eshell echo)
+        "To terminate with a newline, you should use -N instead."))
      (eshell-echo args output-newline))))
 
 (defun eshell/printnl (&rest args)
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index fd76a2c6f0..27e68138aa 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -628,9 +628,10 @@ If QUOTED is non-nil, this was invoked inside 
double-quotes."
               (if (or (eq max-arity 'many) (>= max-arity 2))
                   (funcall target indices quoted)
                 (display-warning
-                 :warning (concat "Function for `eshell-variable-aliases-list' 
"
-                                  "entry should accept two arguments: INDICES "
-                                  "and QUOTED.'"))
+                 '(eshell variable-alias)
+                 (concat "Function for `eshell-variable-aliases-list' "
+                         "entry should accept two arguments: INDICES "
+                         "and QUOTED.'"))
                 (funcall target indices)))))
          ((symbolp target)
           (eshell-apply-indices (symbol-value target) indices quoted))
diff --git a/lisp/files.el b/lisp/files.el
index daa86e94d7..29ba523fa6 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -5059,7 +5059,8 @@ This is a separate procedure so your site-init or startup 
file can
 redefine it.
 If the optional argument KEEP-BACKUP-VERSION is non-nil,
 we do not remove backup version numbers, only true file version numbers.
-See also `file-name-version-regexp'."
+See `file-name-version-regexp' for what constitutes backup versions
+and version strings."
   (let ((handler (find-file-name-handler name 'file-name-sans-versions)))
     (if handler
        (funcall handler 'file-name-sans-versions name keep-backup-version)
@@ -5111,9 +5112,12 @@ the group would be preserved too."
                               (file-attribute-group-id attributes)))))))))))
 
 (defun file-name-sans-extension (filename)
-  "Return FILENAME sans final \"extension\".
+  "Return FILENAME sans final \"extension\" and any backup version strings.
 The extension, in a file name, is the part that begins with the last `.',
-except that a leading `.' of the file name, if there is one, doesn't count."
+except that a leading `.' of the file name, if there is one, doesn't count.
+Any extensions that indicate backup versions and version strings are
+removed by calling `file-name-sans-versions', which see, before looking
+for the \"real\" file extension."
   (save-match-data
     (let ((file (file-name-sans-versions (file-name-nondirectory filename)))
          directory)
@@ -5127,12 +5131,14 @@ except that a leading `.' of the file name, if there is 
one, doesn't count."
        filename))))
 
 (defun file-name-extension (filename &optional period)
-  "Return FILENAME's final \"extension\".
+  "Return FILENAME's final \"extension\" sans any backup version strings.
 The extension, in a file name, is the part that begins with the last `.',
-excluding version numbers and backup suffixes, except that a leading `.'
-of the file name, if there is one, doesn't count.
+except that a leading `.' of the file name, if there is one, doesn't count.
+This function calls `file-name-sans-versions', which see, to remove from
+the extension it returns any parts that indicate backup versions and
+version strings.
 Return nil for extensionless file names such as `foo'.
-Return the empty string for file names such as `foo.'.
+Return the empty string for file names such as `foo.' that end in a period.
 
 By default, the returned value excludes the period that starts the
 extension, but if the optional argument PERIOD is non-nil, the period
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index a14122f815..e21367135d 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -4379,6 +4379,10 @@ NEWNAME should be the name to give the new compressed or 
uncompressed file.")
   ;; or return nil meaning don't make a backup.
   (if ange-ftp-make-backup-files
       (ange-ftp-real-find-backup-file-name fn)))
+
+(defun ange-ftp-file-user-uid ()
+  ;; Return "don't  know" value.
+  -1)
 
 ;;; Define the handler for special file names
 ;;; that causes ange-ftp to be invoked.
@@ -4519,6 +4523,9 @@ NEWNAME should be the name to give the new compressed or 
uncompressed file.")
 (put 'file-notify-add-watch 'ange-ftp 'ignore)
 (put 'file-notify-rm-watch 'ange-ftp 'ignore)
 (put 'file-notify-valid-p 'ange-ftp 'ignore)
+
+;; Return the "don't know' value for remote user uid.
+(put 'file-user-uid 'ange-ftp 'ange-ftp-file-user-uid)
 
 ;;; Define ways of getting at unmodified Emacs primitives,
 ;;; turning off our handler.
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index b9cf85bd84..7c1f578d08 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -670,6 +670,13 @@ offered."
        (setq local (expand-file-name local (file-name-directory localname))))
       (concat (file-truename archive) local))))
 
+(defun tramp-archive-handle-file-user-uid ()
+  "Like `user-uid' for file archives."
+  (with-parsed-tramp-archive-file-name default-directory nil
+    (let ((default-directory (file-name-directory archive)))
+      ;; `file-user-uid' exists since Emacs 30.1.
+      (tramp-compat-funcall 'file-user-uid))))
+
 (defun tramp-archive-handle-insert-directory
   (filename switches &optional wildcard full-directory-p)
   "Like `insert-directory' for file archives."
@@ -702,12 +709,6 @@ offered."
     (let ((default-directory (file-name-directory archive)))
       (temporary-file-directory))))
 
-(defun tramp-archive-handle-file-user-uid ()
-  "Like `user-uid' for file archives."
-  (with-parsed-tramp-archive-file-name default-directory nil
-    (let ((default-directory (file-name-directory archive)))
-      (file-user-uid))))
-
 (defun tramp-archive-handle-not-implemented (operation &rest args)
   "Generic handler for operations not implemented for file archives."
   (let ((v (ignore-errors
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index b9d0d96ecc..afd3166d16 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -204,7 +204,7 @@ If NAME doesn't belong to an encrypted remote directory, 
return nil."
     (file-symlink-p . tramp-handle-file-symlink-p)
     (file-system-info . tramp-crypt-handle-file-system-info)
     ;; `file-truename' performed by default handler.
-    (file-user-uid . tramp-handle-file-user-uid)
+    ;; `file-user-uid' performed by default-handler.
     (file-writable-p . tramp-crypt-handle-file-writable-p)
     (find-backup-file-name . tramp-handle-find-backup-file-name)
     ;; `get-file-buffer' performed by default handler.
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index c066a79815..b3d162cd3a 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -976,6 +976,50 @@ This mode is independent from the classic cc-mode.el based
 
     (treesit-major-mode-setup)))
 
+;; We could alternatively use parsers, but if this works well, I don't
+;; see the need to change.  This is copied verbatim from cc-guess.el.
+(defconst c-ts-mode--c-or-c++-regexp
+  (eval-when-compile
+    (let ((id "[a-zA-Z_][a-zA-Z0-9_]*") (ws "[ \t]+") (ws-maybe "[ \t]*")
+          (headers '("string" "string_view" "iostream" "map" "unordered_map"
+                     "set" "unordered_set" "vector" "tuple")))
+      (concat "^" ws-maybe "\\(?:"
+              "using"     ws "\\(?:namespace" ws
+              "\\|" id "::"
+              "\\|" id ws-maybe "=\\)"
+              "\\|" "\\(?:inline" ws "\\)?namespace"
+              "\\(:?" ws "\\(?:" id "::\\)*" id "\\)?" ws-maybe "{"
+              "\\|" "class"     ws id
+              "\\(?:" ws "final" "\\)?" ws-maybe "[:{;\n]"
+              "\\|" "struct"     ws id "\\(?:" ws "final" ws-maybe "[:{\n]"
+              "\\|" ws-maybe ":\\)"
+              "\\|" "template"  ws-maybe "<.*?>"
+              "\\|" "#include"  ws-maybe "<" (regexp-opt headers) ">"
+              "\\)")))
+  "A regexp applied to C header files to check if they are really C++.")
+
+;;;###autoload
+(defun c-or-c++-ts-mode ()
+  "Analyze buffer and enable either C or C++ mode.
+
+Some people and projects use .h extension for C++ header files
+which is also the one used for C header files.  This makes
+matching on file name insufficient for detecting major mode that
+should be used.
+
+This function attempts to use file contents to determine whether
+the code is C or C++ and based on that chooses whether to enable
+`c-ts-mode' or `c++-ts-mode'."
+  (interactive)
+  (if (save-excursion
+        (save-restriction
+          (save-match-data ; Why `save-match-data'?
+            (widen)
+            (goto-char (point-min))
+            (re-search-forward c-ts-mode--c-or-c++-regexp nil t))))
+      (c++-ts-mode)
+    (c-ts-mode)))
+
 (provide 'c-ts-mode)
 
 ;;; c-ts-mode.el ends here
diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el
index 493035d38b..bdbc03e7c9 100644
--- a/lisp/progmodes/cc-defs.el
+++ b/lisp/progmodes/cc-defs.el
@@ -1361,6 +1361,28 @@ nil; point is then left undefined."
        (search-forward-regexp "\\(\n\\|.\\)")  ; to set the match-data.
        (point))))
 
+(defmacro c-search-forward-non-nil-char-property (property &optional limit)
+  "Search forward for a text-property PROPERTY value non-nil.
+LIMIT bounds the search.
+
+Leave point just after the character.  The match data remain
+unchanged.  Return the value of PROPERTY.  If a non-nil value
+isn't found, return nil; point is then left undefined."
+  (declare (debug t))
+  `(let* ((-limit- (or ,limit (point-max)))
+         (value (c-get-char-property (point) ,property)))
+     (cond
+      ((>= (point) -limit-)
+       nil)
+      (value
+       (forward-char)
+       value)
+      (t (let ((place (c-next-single-property-change
+                      (point) ,property nil -limit-)))
+          (when place
+            (goto-char (1+ place))
+            (c-get-char-property place ,property)))))))
+
 (defmacro c-search-backward-char-property (property value &optional limit)
   "Search backward for a text-property PROPERTY having value VALUE.
 LIMIT bounds the search.  The comparison is done with `equal'.
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 45d90ea243..3fa407dd33 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -142,6 +142,10 @@
 ;;       Put on the brace which introduces a brace list and on the commas
 ;;       which separate the elements within it.
 ;;
+;; 'c-typedef This property is applied to the first character of a
+;;   "typedef" keyword.  It's value is a list of the identifiers that
+;;   the "typedef" declares as types.
+;;
 ;; 'c-<>-c-types-set
 ;;   This property is set on an opening angle bracket, and indicates that
 ;;   any "," separators within the template/generic expression have been
@@ -10024,10 +10028,10 @@ This function might do hidden buffer changes."
   ;; an identifier instead.
   (declare (debug nil))
   `(progn
+     (setq identifier-start type-start)
      ,(unless short
        ;; These identifiers are bound only in the inner let.
        '(setq identifier-type at-type
-              identifier-start type-start
               got-parens nil
               got-identifier t
               got-suffix t
@@ -10102,10 +10106,11 @@ This function might do hidden buffer changes."
   ;;   The second element of the return value is non-nil when something
   ;;   indicating the identifier is a type occurs in the declaration.
   ;;   Specifically it is nil, or a three element list (A B C) where C is t
-  ;;   when context is '<> and the "identifier" is a found type, B is t when a
-  ;;   `c-typedef-kwds' ("typedef") is present, and A is t when some other
-  ;;   `c-typedef-decl-kwds' (e.g. class, struct, enum) specifier is present.
-  ;;   I.e., (some of) the declared identifier(s) are types.
+  ;;   when context is '<> and the "identifier" is a found type, B is the
+  ;;   position of the `c-typedef-kwds' keyword ("typedef") when such is
+  ;;   present, and A is t when some other `c-typedef-decl-kwds' (e.g. class,
+  ;;   struct, enum) specifier is present.  I.e., (some of) the declared
+  ;;   identifier(s) are types.
   ;;
   ;;   The third element of the return value is non-nil when the declaration
   ;;   parsed might be an expression.  The fourth element is the position of
@@ -10173,6 +10178,9 @@ This function might do hidden buffer changes."
        ;; `c-decl-hangon-kwds' and their associated clauses that
        ;; occurs after the type.
        id-start
+       ;; The earlier value of `type-start' if we've shifted the type
+       ;; backwards.
+       identifier-start
        ;; These store `at-type', `type-start' and `id-start' of the
        ;; identifier before the one in those variables.  The previous
        ;; identifier might turn out to be the real type in a
@@ -10183,7 +10191,8 @@ This function might do hidden buffer changes."
        ;; Set if we've found a specifier (apart from "typedef") that makes
        ;; the defined identifier(s) types.
        at-type-decl
-       ;; Set if we've a "typedef" keyword.
+       ;; If we've a "typedef" keyword (?or similar), the buffer position of
+       ;; its first character.
        at-typedef
        ;; Set if `context' is '<> and the identifier is definitely a type, or
        ;; has already been recorded as a found type.
@@ -10266,7 +10275,7 @@ This function might do hidden buffer changes."
                 (looking-at "@[A-Za-z0-9]+")))
            (save-match-data
              (if (looking-at c-typedef-key)
-                 (setq at-typedef t)))
+                 (setq at-typedef (point))))
            (setq kwd-sym (c-keyword-sym (match-string 1)))
            (save-excursion
              (c-forward-keyword-clause 1)
@@ -10486,9 +10495,9 @@ This function might do hidden buffer changes."
          ;; True if we've parsed the type decl to a token that is
          ;; known to end declarations in this context.
          at-decl-end
-         ;; The earlier values of `at-type' and `type-start' if we've
-         ;; shifted the type backwards.
-         identifier-type identifier-start
+         ;; The earlier value of `at-type' if we've shifted the type
+         ;; backwards.
+         identifier-type
          ;; If `c-parse-and-markup-<>-arglists' is set we need to
          ;; turn it off during the name skipping below to avoid
          ;; getting `c-type' properties that might be bogus.  That
@@ -10530,6 +10539,10 @@ This function might do hidden buffer changes."
                              (progn (setq got-identifier nil) t)
                            ;; It turned out to be the real identifier,
                            ;; so stop.
+                           (save-excursion
+                             (c-backward-syntactic-ws)
+                             (c-simple-skip-symbol-backward)
+                             (setq identifier-start (point)))
                            nil))
                      t))
 
@@ -10555,6 +10568,10 @@ This function might do hidden buffer changes."
          (and (looking-at c-identifier-start)
               (setq pos (point))
               (setq got-identifier (c-forward-name))
+              (save-excursion
+                (c-backward-syntactic-ws)
+                (c-simple-skip-symbol-backward)
+                (setq identifier-start (point)))
               (setq name-start pos))
          (when (looking-at "[0-9]")
            (setq got-number t)) ; We probably have an arithmetic expression.
@@ -10573,7 +10590,8 @@ This function might do hidden buffer changes."
               (setq at-type nil
                     name-start type-start
                     id-start type-start
-                    got-identifier t)))
+                    got-identifier t)
+              (setq identifier-start type-start)))
 
       ;; Skip over type decl suffix operators and trailing noise macros.
       (while
diff --git a/lisp/progmodes/cc-fonts.el b/lisp/progmodes/cc-fonts.el
index 4dcc3e0ade..c220d8d878 100644
--- a/lisp/progmodes/cc-fonts.el
+++ b/lisp/progmodes/cc-fonts.el
@@ -85,6 +85,8 @@
 
 (cc-bytecomp-defvar parse-sexp-lookup-properties) ; Emacs only.
 
+(declare-function cl-set-difference "cl-seq" (cl-list1 cl-list2 &rest cl-keys))
+
 ;; Need to declare these local symbols during compilation since
 ;; they're referenced from lambdas in `byte-compile' calls that are
 ;; executed at compile time.  They don't need to have the proper
@@ -1109,10 +1111,12 @@ casts and declarations are fontified.  Used on level 2 
and higher."
   ;; additionally, mark the commas with c-type property 'c-decl-id-start or
   ;; 'c-decl-type-start (according to TYPES).  Stop at LIMIT.
   ;;
-  ;; If TYPES is t, fontify all identifiers as types, if it is nil fontify as
-  ;; either variables or functions, otherwise TYPES is a face to use.  If
-  ;; NOT-TOP is non-nil, we are not at the top-level ("top-level" includes
-  ;; being directly inside a class or namespace, etc.).
+  ;; If TYPES is t, fontify all identifiers as types; if it is a number, a
+  ;; buffer position, additionally set the `c-deftype' text property on the
+  ;; keyword at that position; if it is nil fontify as either variables or
+  ;; functions, otherwise TYPES is a face to use.  If NOT-TOP is non-nil, we
+  ;; are not at the top-level ("top-level" includes being directly inside a
+  ;; class or namespace, etc.).
   ;;
   ;; TEMPLATE-CLASS is non-nil when the declaration is in template delimiters
   ;; and was introduced by, e.g. "typename" or "class", such that if there is
@@ -1129,17 +1133,28 @@ casts and declarations are fontified.  Used on level 2 
and higher."
   ;;(message "c-font-lock-declarators from %s to %s" (point) limit)
   (c-fontify-types-and-refs
       ()
+    ;; If we're altering the declarators in a typedef, we need to scan ALL of
+    ;; them because of the way we check for changes.
+    (let ((c-do-decl-limit (if (numberp types) (point-max) limit))
+         decl-ids)
     (c-do-declarators
-     limit list not-top
-     (cond ((eq types t) 'c-decl-type-start)
+     c-do-decl-limit
+     list not-top
+     (cond ((or (numberp types)
+               (eq types t))
+           'c-decl-type-start)
           ((null types) 'c-decl-id-start))
      (lambda (id-start id-end end-pos _not-top is-function init-char)
-       (if (eq types t)
+       (if (or (numberp types)
+              (eq types t))
           (when id-start
             ;; Register and fontify the identifier as a type.
             (let ((c-promote-possible-types t))
               (goto-char id-start)
-              (c-forward-type)))
+              (c-forward-type))
+            (when (numberp types)
+              (push (buffer-substring-no-properties id-start id-end)
+                    decl-ids)))
         (when id-start
           (goto-char id-start)
           (when c-opt-identifier-prefix-key
@@ -1147,7 +1162,7 @@ casts and declarations are fontified.  Used on level 2 
and higher."
                          (eq (match-end 1) id-end))
               (while (and (< (point) id-end)
                           (re-search-forward c-opt-identifier-prefix-key 
id-end t))
-                (c-forward-syntactic-ws limit))))
+                (c-forward-syntactic-ws c-do-decl-limit))))
           ;; Only apply the face when the text doesn't have one yet.
           ;; Exception: The "" in C++'s operator"" will already wrongly have
           ;; string face.
@@ -1164,7 +1179,7 @@ casts and declarations are fontified.  Used on level 2 
and higher."
                  (equal (buffer-substring-no-properties id-start id-end)
                         "\"\""))
             (goto-char id-end)
-            (c-forward-syntactic-ws limit)
+            (c-forward-syntactic-ws c-do-decl-limit)
             (when (c-on-identifier)
               (c-put-font-lock-face
                (point)
@@ -1174,10 +1189,21 @@ casts and declarations are fontified.  Used on level 2 
and higher."
            (eq init-char ?=)           ; C++ "<class X = Y>"?
            (progn
              (goto-char end-pos)
-             (c-forward-token-2 1 nil limit) ; Over "="
+             (c-forward-token-2 1 nil c-do-decl-limit) ; Over "="
              (let ((c-promote-possible-types t))
                (c-forward-type t)))))
      accept-anon)                      ; Last argument to c-do-declarators.
+    ;; If we've changed types declared by a "typedef", update the `c-typedef'
+    ;; text property.
+    (when (numberp types)
+      (let* ((old-decl-ids (c-get-char-property types 'c-typedef))
+            (old-types (c--set-difference old-decl-ids decl-ids :test #'equal))
+            (new-types (c--set-difference decl-ids old-decl-ids :test 
#'equal)))
+       (dolist (type old-types)
+         (c-unfind-type type))
+       ;; The new types have already been added to `c-found-types', as needed.
+       (when (or old-types new-types)
+         (c-put-char-property types 'c-typedef decl-ids)))))
     nil))
 
 (defun c-get-fontification-context (match-pos not-front-decl &optional toplev)
@@ -1433,7 +1459,10 @@ casts and declarations are fontified.  Used on level 2 
and higher."
       (c-font-lock-declarators
        (min limit (point-max))
        decl-list
-       (not (null (cadr decl-or-cast)))
+       (cond ((null (cadr decl-or-cast))
+             nil)
+            ((cadr (cadr decl-or-cast)))
+            (t t))
        (not toplev)
        template-class
        (memq context '(decl <>))))
@@ -1749,12 +1778,21 @@ casts and declarations are fontified.  Used on level 2 
and higher."
                                        ; speeds up lisp.h tremendously.
       (save-excursion
        (when (not (c-back-over-member-initializers decl-search-lim))
+         (setq paren-state (c-parse-state))
          (unless (or (eobp)
                      (looking-at "\\s(\\|\\s)"))
            (forward-char))
          (c-syntactic-skip-backward "^;{}" decl-search-lim t)
-         (when (eq (char-before) ?})
-           (c-go-list-backward)        ; brace block of struct, etc.?
+         ;; Do we have the brace block of a struct, etc.?
+         (when (cond
+                ((and (consp (car paren-state))
+                      (eq (char-before) ?}))
+                 (goto-char (caar paren-state))
+                 t)
+                ((and (numberp (car paren-state))
+                      (eq (char-after (car paren-state)) ?{))
+                 (goto-char (car paren-state))
+                 t))
            (c-syntactic-skip-backward "^;{}" decl-search-lim t))
          (when (or (bobp)
                    (memq (char-before) '(?\; ?{ ?})))
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index b04ed7584c..330202bb5f 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -2077,6 +2077,37 @@ with // and /*, not more generic line and block 
comments."
                 (not (eobp))))
        (forward-char))))))
 
+(defun c-before-change-de-typedef (beg end)
+  ;; For each "typedef" starting in (BEG END), remove the defined types from
+  ;; c-found-types
+  (let (prop)
+    (save-excursion
+      (goto-char beg)
+      (while (and (< (point) end)
+                 (setq prop (c-search-forward-non-nil-char-property
+                             'c-typedef)))
+       (dolist (type prop)
+         (c-unfind-type type))))))
+
+(defun c-after-change-de-typedef (beg end _old-len)
+  ;; For each former "typedef" in (BEG END), remove the defined types from
+  ;; those which are no longer typedefs.
+  (let (prop)
+    (save-excursion
+      (goto-char beg)
+      (c-backward-token-2
+       1 nil (- (point) 20))
+      (while (and (< (point) end)
+                 (setq prop (c-search-forward-non-nil-char-property
+                             'c-typedef end)))
+       (backward-char)
+       (when (or (not (looking-at c-typedef-key))
+                 (<= (match-end 1) beg))
+         (dolist (type prop)
+           (c-unfind-type type))
+         (c-clear-char-property (point) 'c-typedef))
+       (forward-char)))))
+
 (defun c-update-new-id (end)
   ;; Note the bounds of any identifier that END is in or just after, in
   ;; `c-new-id-start' and `c-new-id-end'.  Otherwise set these variables to
@@ -2086,7 +2117,9 @@ with // and /*, not more generic line and block comments."
     (let ((id-beg (c-on-identifier)))
       (setq c-new-id-start id-beg
            c-new-id-end (and id-beg
-                             (progn (c-end-of-current-token) (point)))
+                             (progn (goto-char id-beg)
+                                    (c-forward-token-2)
+                                    (point)))
            c-new-id-is-type nil))))
 
 (defun c-post-command ()
@@ -2215,6 +2248,10 @@ with // and /*, not more generic line and block 
comments."
                                                               term-pos)
                               (buffer-substring-no-properties beg end)))))))
 
+          ;; If we're about to delete "typedef"s, clear the identifiers from
+          ;; `c-found-types'.
+          (c-before-change-de-typedef beg end)
+
           (if c-get-state-before-change-functions
               (mapc (lambda (fn)
                       (funcall fn beg end))
@@ -2306,6 +2343,7 @@ with // and /*, not more generic line and block comments."
           (c-update-new-id end)
           (c-trim-found-types beg end old-len) ; maybe we don't
                                        ; need all of these.
+          (c-after-change-de-typedef beg end old-len)
           (c-invalidate-sws-region-after beg end old-len)
           ;; (c-invalidate-state-cache beg) ; moved to
           ;; `c-before-change'.
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index 939c054b04..f075824591 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -152,7 +152,6 @@
           "then"
           "ensure"
           "body_statement"
-          "parenthesized_statements"
           "interpolation")
       string-end)
   "Regular expression of the nodes that can contain statements.")
@@ -221,9 +220,9 @@ values of OVERRIDE"
 
    :language language
    :feature 'constant
-   '((true) @font-lock-doc-markup-face
-     (false) @font-lock-doc-markup-face
-     (nil) @font-lock-doc-markup-face)
+   '((true) @font-lock-constant-face
+     (false) @font-lock-constant-face
+     (nil) @font-lock-constant-face)
 
    ;; Before 'operator so (unary) works.
    :language language
@@ -512,10 +511,6 @@ array or hash."
          (first-child (ruby-ts--first-non-comment-child parent)))
     (= (ruby-ts--lineno open-brace) (ruby-ts--lineno first-child))))
 
-(defun ruby-ts--assignment-ancestor (node &rest _)
-  "Return the assignment ancestor of NODE if any."
-  (treesit-parent-until node (ruby-ts--type-pred "\\`assignment\\'")))
-
 (defun ruby-ts--statement-ancestor (node &rest _)
   "Return the statement ancestor of NODE if any.
 A statement is defined as a child of a statement container where
@@ -531,26 +526,6 @@ a statement container is a node that matches
             parent (treesit-node-parent parent)))
     statement))
 
-(defun ruby-ts--is-in-condition (node &rest _)
-  "Return the condition node if NODE is within a condition."
-  (while (and node
-              (not (equal "condition" (treesit-node-field-name node)))
-              (not (string-match-p ruby-ts--statement-container-regexp
-                                   (treesit-node-type node))))
-    (setq node (treesit-node-parent node)))
-  (and (equal "condition" (treesit-node-field-name node)) node))
-
-(defun ruby-ts--endless-method (node &rest _)
-  "Return the expression node if NODE is in an endless method.
-i.e. expr of def foo(args) = expr is returned."
-  (let* ((method node))
-    (while (and method
-                (not (string-match-p ruby-ts--method-regex (treesit-node-type 
method))))
-      (setq method (treesit-node-parent method)))
-    (when method
-      (if (equal "=" (treesit-node-type (treesit-node-child method 3 nil)))
-          (treesit-node-child method 4 nil)))))
-
 ;;
 ;; end of functions that can be used for queries
 ;;
@@ -587,11 +562,11 @@ i.e. expr of def foo(args) = expr is returned."
            ;;
            ;; I'm using very restrictive patterns hoping to reduce rules
            ;; triggering unintentionally.
-           ((match "else" "if")
+           ((match "else" "if\\|unless")
             (ruby-ts--align-keywords ruby-ts--parent-node) 0)
            ((match "elsif" "if")
             (ruby-ts--align-keywords ruby-ts--parent-node) 0)
-           ((match "end" "if")
+           ((match "end" "if\\|unless")
             (ruby-ts--align-keywords ruby-ts--parent-node) 0)
            ((n-p-gp nil "then\\|else\\|elsif" "if\\|unless")
             (ruby-ts--align-keywords ruby-ts--grand-parent-node) 
ruby-indent-level)
@@ -664,6 +639,13 @@ i.e. expr of def foo(args) = expr is returned."
            ;; else the second query aligns
            ;; `ruby-indent-level' spaces in from the parent.
            ((and ruby-ts--align-chain-p (match "\\." "call")) 
ruby-ts--align-chain 0)
+           ;; Obery ruby-method-call-indent, whether the dot is on
+           ;; this line or the previous line.
+           ((and (not ruby-ts--method-call-indent-p)
+                 (or
+                  (match "\\." "call")
+                  (query "(call \".\" (identifier) @indent)")))
+            parent 0)
            ((match "\\." "call") parent ruby-indent-level)
 
            ;; ruby-indent-after-block-in-continued-expression
@@ -697,23 +679,27 @@ i.e. expr of def foo(args) = expr is returned."
            ;; 2) With paren, 1st arg on next line
            ((and (query "(argument_list \"(\" _ @indent)")
                  (node-is ")"))
-            (ruby-ts--bol ruby-ts--grand-parent-node) 0)
+            ruby-ts--parent-call-or-bol 0)
            ((query "(argument_list \"(\" _ @indent)")
-            (ruby-ts--bol ruby-ts--grand-parent-node) ruby-indent-level)
+            ruby-ts--parent-call-or-bol ruby-indent-level)
            ;; 3) No paren, ruby-parenless-call-arguments-indent is t
            ((and ruby-ts--parenless-call-arguments-indent-p (parent-is 
"argument_list"))
             first-sibling 0)
            ;; 4) No paren, ruby-parenless-call-arguments-indent is nil
-           ((parent-is "argument_list") (ruby-ts--bol 
ruby-ts--grand-parent-node) ruby-indent-level)
+           ((parent-is "argument_list")
+            (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
 
            ;; Old... probably too simple
            ((parent-is "block_parameters") first-sibling 1)
 
-           ((and (parent-is "binary")
-                 (or ruby-ts--assignment-ancestor
-                     ruby-ts--is-in-condition
-                     ruby-ts--endless-method))
-            first-sibling 0)
+           ((and (not ruby-ts--after-op-indent-p)
+                 (parent-is "binary\\|conditional"))
+            (ruby-ts--bol ruby-ts--statement-ancestor) ruby-indent-level)
+
+           ((parent-is "binary")
+            ruby-ts--binary-indent-anchor 0)
+
+           ((parent-is "conditional") parent ruby-indent-level)
 
            ;; ruby-mode does not touch these...
            ((match "bare_string" "string_array") no-indent 0)
@@ -732,37 +718,15 @@ i.e. expr of def foo(args) = expr is returned."
            ((and ruby-ts--same-line-hash-array-p (parent-is "array"))
             (nth-sibling 0 ruby-ts--true) 0)
 
-           ;; NOTE to folks trying to understand my insanity...
-           ;; I having trouble understanding the "logic" of why things
-           ;; are indented like they are so I am adding special cases
-           ;; hoping at some point I will be struck by lightning.
-           ((and (n-p-gp "}" "hash" "pair")
-                 (not ruby-ts--same-line-hash-array-p))
-            grand-parent 0)
-           ((and (n-p-gp "pair" "hash" "pair")
-                 (not ruby-ts--same-line-hash-array-p))
-            grand-parent ruby-indent-level)
-           ((and (n-p-gp "}" "hash" "method")
-                 (not ruby-ts--same-line-hash-array-p))
-            grand-parent 0)
-           ((and (n-p-gp "pair" "hash" "method")
-                 (not ruby-ts--same-line-hash-array-p))
-            grand-parent ruby-indent-level)
-
-           ((n-p-gp "}" "hash" "assignment")  (ruby-ts--bol 
ruby-ts--grand-parent-node) 0)
-           ((n-p-gp nil "hash" "assignment")  (ruby-ts--bol 
ruby-ts--grand-parent-node) ruby-indent-level)
-           ((n-p-gp "]" "array" "assignment") (ruby-ts--bol 
ruby-ts--grand-parent-node) 0)
-           ((n-p-gp nil "array" "assignment") (ruby-ts--bol 
ruby-ts--grand-parent-node) ruby-indent-level)
-
-           ((n-p-gp "}" "hash" "argument_list")  first-sibling 0)
-           ((n-p-gp nil "hash" "argument_list")  first-sibling 
ruby-indent-level)
-           ((n-p-gp "]" "array" "argument_list") first-sibling 0)
-           ((n-p-gp nil "array" "argument_list") first-sibling 
ruby-indent-level)
-
-           ((match "}" "hash")  first-sibling 0)
-           ((parent-is "hash")  first-sibling ruby-indent-level)
-           ((match "]" "array") first-sibling 0)
-           ((parent-is "array") first-sibling ruby-indent-level)
+           ((match "}" "hash")  ruby-ts--parent-call-or-bol 0)
+           ((parent-is "hash")  ruby-ts--parent-call-or-bol ruby-indent-level)
+           ((match "]" "array") ruby-ts--parent-call-or-bol 0)
+           ((parent-is "array") ruby-ts--parent-call-or-bol ruby-indent-level)
+
+           ((parent-is "pair") ruby-ts--parent-call-or-bol 0)
+
+           ((match ")" "parenthesized_statements") parent-bol 0)
+           ((parent-is "parenthesized_statements") parent-bol 
ruby-indent-level)
 
            ;; If the previous method isn't finished yet, this will get
            ;; the next method indented properly.
@@ -814,6 +778,66 @@ i.e. expr of def foo(args) = expr is returned."
         (back-to-indentation)
         (point)))))
 
+(defun ruby-ts--binary-indent-anchor (_node parent _bol &rest _)
+  (save-excursion
+    (goto-char (treesit-node-start parent))
+    (when (string-match-p ruby-ts--statement-container-regexp
+                          (treesit-node-type (treesit-node-parent parent)))
+      ;; Hack alert: it's not the proper place to alter the offset.
+      ;; Redoing the analysis in the OFFSET form seems annoying,
+      ;; though. (**)
+      (forward-char ruby-indent-level))
+    (point)))
+
+(defun ruby-ts--parent-call-or-bol (_not parent _bol &rest _)
+  (let* ((parent-bol (save-excursion
+                       (goto-char (treesit-node-start parent))
+                       (back-to-indentation)
+                       (point)))
+         (found
+          (treesit-parent-until
+           parent
+           (lambda (node)
+             (or (< (treesit-node-start node) parent-bol)
+                 (string-match-p "\\`array\\|hash\\'" (treesit-node-type node))
+                 ;; Method call on same line.
+                 (equal (treesit-node-type node) "argument_list"))))))
+    (cond
+     ((null found)
+      parent-bol)
+     ;; No paren/curly/brace found on the same line.
+     ((< (treesit-node-start found) parent-bol)
+      parent-bol)
+     ;; Hash or array opener on the same line.
+     ((string-match-p "\\`array\\|hash\\'" (treesit-node-type found))
+      (save-excursion
+        (goto-char (treesit-node-start (treesit-node-child found 1)))
+        (point)))
+     ;; Parenless call found: indent to stmt with offset.
+     ((not ruby-parenless-call-arguments-indent)
+      (save-excursion
+        (goto-char (treesit-node-start
+                    (ruby-ts--statement-ancestor found)))
+        ;; (**) Same.
+        (+ (point) ruby-indent-level)))
+     ;; Call with parens -- ident to first arg.
+     ((equal (treesit-node-type (treesit-node-child found 0))
+             "(")
+      (save-excursion
+        (goto-char (treesit-node-start (treesit-node-child found 1)))
+        (point)))
+     ;; Indent to the parenless call args beginning.
+     (t
+      (save-excursion
+        (goto-char (treesit-node-start found))
+        (point))))))
+
+(defun ruby-ts--after-op-indent-p (&rest _)
+  ruby-after-operator-indent)
+
+(defun ruby-ts--method-call-indent-p (&rest _)
+  ruby-method-call-indent)
+
 (defun ruby-ts--class-or-module-p (node)
   "Predicate if NODE is a class or module."
   (string-match-p ruby-ts--class-or-module-regex (treesit-node-type node)))
diff --git a/lisp/replace.el b/lisp/replace.el
index 2f063bbf66..3c2b925ea9 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -824,11 +824,11 @@ by this function to the end of values available via
 
 (defvar-keymap read-regexp-map
   :parent minibuffer-local-map
-  "M-c" #'read-regexp-toggle-case-folding)
+  "M-s c" #'read-regexp-toggle-case-fold)
 
 (defvar read-regexp--case-fold nil)
 
-(defun read-regexp-toggle-case-folding ()
+(defun read-regexp-toggle-case-fold ()
   (interactive)
   (setq read-regexp--case-fold
         (if (or (eq read-regexp--case-fold 'fold)
@@ -875,7 +875,7 @@ in \":\", followed by optional whitespace), DEFAULT is 
added to the prompt.
 The optional argument HISTORY is a symbol to use for the history list.
 If nil, use `regexp-history'.
 
-If the user has used the 
\\<read-regexp-map>\\[read-regexp-toggle-case-folding] command to specify case
+If the user has used the \\<read-regexp-map>\\[read-regexp-toggle-case-fold] 
command to specify case
 sensitivity, the returned string will have a text property named
 `case-fold' that has a value of either `fold' or
 `inhibit-fold'.  (It's up to the caller of `read-regexp' to
diff --git a/lisp/treesit.el b/lisp/treesit.el
index 69bfff21df..e8571d43db 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -905,6 +905,14 @@ This is not a general optimization and should be RARELY 
needed!
 See comments in `treesit-font-lock-fontify-region' for more
 detail.")
 
+(defvar-local treesit--font-lock-fast-mode-grace-count 5
+  "Grace counts before we turn on the fast mode.
+
+When query takes abnormally long time to execute, we turn on the
+\"fast mode\", but just to be on the safe side, we only turn on
+the fast mode after this number of offenses.  See bug#60691,
+bug#60223.")
+
 ;; Some details worth explaining:
 ;;
 ;; 1. When we apply face to a node, we clip the face into the
@@ -927,13 +935,13 @@ detail.")
 ;; parse it into a enormously tall tree (10k levels tall).  In that
 ;; case querying the root node is very slow.  So we try to get
 ;; top-level nodes and query them.  This ensures that querying is fast
-;; everywhere else, except for the problematic region.
+;; everywhere else, except for the problematic region.  (Bug#59415).
 ;;
 ;; Some other time the source file has a top-level node that contains
-;; a huge number of children (say, 10k children), querying that node
-;; is also very slow, so instead of getting the top-level node, we
-;; recursively go down the tree to find nodes that cover the region
-;; but are reasonably small.
+;; a huge number of immediate children (say, 10k children), querying
+;; that node is also very slow, so instead of getting the top-level
+;; node, we recursively go down the tree to find nodes that cover the
+;; region but are reasonably small.  (Bug#59738).
 ;;
 ;; 3. It is possible to capture a node that's completely outside the
 ;; region between START and END: as long as the whole pattern
@@ -941,8 +949,8 @@ detail.")
 ;; returned.  If the node is outside of that region, (max node-start
 ;; start) and friends return bad values, so we filter them out.
 ;; However, we don't filter these nodes out if a function will process
-;; the node, because could (and often do) fontify the relatives of the
-;; captured node, not just the node itself.  If we took out those
+;; the node, because it could (and often do) fontify the relatives of
+;; the captured node, not just the node itself.  If we took out those
 ;; nodes author of those functions would be very confused.
 (defun treesit-font-lock-fontify-region (start end &optional loudly)
   "Fontify the region between START and END.
@@ -979,9 +987,12 @@ If LOUDLY is non-nil, display some debugging information."
                  (end-time (current-time)))
             ;; If for any query the query time is strangely long,
             ;; switch to fast mode (see comments above).
-            (when (> (time-to-seconds (time-subtract end-time start-time))
-                     0.01)
-              (setq-local treesit--font-lock-fast-mode t))
+            (when (and (> (time-to-seconds
+                           (time-subtract end-time start-time))
+                          0.01))
+              (if (> treesit--font-lock-fast-mode-grace-count 0)
+                  (cl-decf treesit--font-lock-fast-mode-grace-count)
+                (setq-local treesit--font-lock-fast-mode t)))
 
             ;; For each captured node, fontify that node.
             (with-silent-modifications
@@ -1152,6 +1163,9 @@ See `treesit-simple-indent-presets'.")
                     (and (>= (point) comment-start-bol)
                          adaptive-fill-regexp
                          (looking-at adaptive-fill-regexp)
+                         ;; If previous line is an empty line, don't
+                         ;; indent.
+                         (not (looking-at (rx (* whitespace) eol)))
                          (match-end 0))))))
         ;; TODO: Document.
         (cons 'grand-parent
diff --git a/lisp/vc/vc-dir.el b/lisp/vc/vc-dir.el
index 312556f644..53d58870b3 100644
--- a/lisp/vc/vc-dir.el
+++ b/lisp/vc/vc-dir.el
@@ -325,7 +325,6 @@ See `run-hooks'."
     (define-key map "U" #'vc-dir-unmark-all-files)
     (define-key map "\C-?" #'vc-dir-unmark-file-up)
     (define-key map "\M-\C-?" #'vc-dir-unmark-all-files)
-    (define-key map "%" #'vc-dir-mark-by-regexp)
     ;; Movement.
     (define-key map "n" #'vc-dir-next-line)
     (define-key map " " #'vc-dir-next-line)
@@ -361,8 +360,13 @@ See `run-hooks'."
       (define-key branch-map "l" #'vc-print-branch-log)
       (define-key branch-map "s" #'vc-switch-branch))
 
+    (let ((regexp-map (make-sparse-keymap)))
+      (define-key map "%" regexp-map)
+      (define-key regexp-map "m" #'vc-dir-mark-by-regexp))
+
     (let ((mark-map (make-sparse-keymap)))
       (define-key map "*" mark-map)
+      (define-key mark-map "%" #'vc-dir-mark-by-regexp)
       (define-key mark-map "r" #'vc-dir-mark-registered-files))
 
     ;; Hook up the menu.
@@ -791,7 +795,7 @@ MARK-FILES should be a list of absolute filenames."
    vc-ewoc))
 
 (defun vc-dir-mark-registered-files ()
-  "Mark files that are in one of registered state: edited, added or removed."
+  "Mark files that are in one of registered states: edited, added or removed."
   (interactive)
   (vc-dir-mark-state-files '(edited added removed)))
 
diff --git a/lisp/window.el b/lisp/window.el
index 4099b70700..84f5c5c3f5 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -5670,7 +5670,8 @@ the original point in both windows."
 
 (defun split-window-below (&optional size window-to-split)
   "Split WINDOW-TO-SPLIT into two windows, one above the other.
-WINDOW-TO-SPLIT is above.  The newly split-off window is
+WINDOW-TO-SPLIT defaults to the selected window and and will be above
+the other window after splitting.  The newly split-off window is
 below and displays the same buffer.  Return the new window.
 
 If optional argument SIZE is omitted or nil, both windows get the
@@ -5691,7 +5692,9 @@ amount of redisplay; this is convenient on slow 
terminals."
       ;; `split-window' would not signal an error here.
       (error "Size of new window too small"))
     (setq new-window (split-window window-to-split size))
-    (unless split-window-keep-point
+    (when (and (null split-window-keep-point)
+               (or (null window-to-split)
+                   (eq window-to-split (selected-window))))
       (with-current-buffer (window-buffer window-to-split)
        ;; Use `save-excursion' around vertical movements below
        ;; (Bug#10971).  Note: When WINDOW-TO-SPLIT's buffer has a
@@ -5732,8 +5735,9 @@ handled as in `split-window-below'."
 
 (defun split-window-right (&optional size window-to-split)
   "Split WINDOW-TO-SPLIT into two side-by-side windows.
-WINDOW-TO-SPLIT is on the left.  The newly split-off window is on
-the right and displays the same buffer.  Return the new window.
+WINDOW-TO-SPLIT defaults to the selected window and and will be on the
+left after splitting.  The newly split-off window is on the right and
+displays the same buffer.  Return the new window.
 
 If optional argument SIZE is omitted or nil, both windows get the
 same width, or close to it.  If SIZE is positive, the left-hand
diff --git a/src/buffer.c b/src/buffer.c
index 100e42fc1f..88ca69b0dd 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -525,14 +525,14 @@ get_truename_buffer (register Lisp_Object filename)
   return Qnil;
 }
 
-/* Run buffer-list-update-hook if Vrun_hooks is non-nil, and BUF is NULL
-   or does not have buffer hooks inhibited.  BUF is NULL when called by
-   make-indirect-buffer, since it does not inhibit buffer hooks.  */
+/* Run buffer-list-update-hook if Vrun_hooks is non-nil and BUF does
+   not have buffer hooks inhibited.  */
 
 static void
 run_buffer_list_update_hook (struct buffer *buf)
 {
-  if (! (NILP (Vrun_hooks) || (buf && buf->inhibit_buffer_hooks)))
+  eassert (buf);
+  if (! (NILP (Vrun_hooks) || buf->inhibit_buffer_hooks))
     call1 (Vrun_hooks, Qbuffer_list_update_hook);
 }
 
@@ -907,7 +907,7 @@ does not run the hooks `kill-buffer-hook',
       set_buffer_internal_1 (old_b);
     }
 
-  run_buffer_list_update_hook (NULL);
+  run_buffer_list_update_hook (b);
 
   return buf;
 }
diff --git a/src/treesit.c b/src/treesit.c
index 3886fed346..917db58267 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -42,8 +42,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #undef ts_node_end_byte
 #undef ts_node_eq
 #undef ts_node_field_name_for_child
-#undef ts_node_first_child_for_byte
-#undef ts_node_first_named_child_for_byte
 #undef ts_node_has_error
 #undef ts_node_is_extra
 #undef ts_node_is_missing
@@ -99,8 +97,6 @@ DEF_DLL_FN (TSNode, ts_node_descendant_for_byte_range,
 DEF_DLL_FN (uint32_t, ts_node_end_byte, (TSNode));
 DEF_DLL_FN (bool, ts_node_eq, (TSNode, TSNode));
 DEF_DLL_FN (const char *, ts_node_field_name_for_child, (TSNode, uint32_t));
-DEF_DLL_FN (TSNode, ts_node_first_child_for_byte, (TSNode, uint32_t));
-DEF_DLL_FN (TSNode, ts_node_first_named_child_for_byte, (TSNode, uint32_t));
 DEF_DLL_FN (bool, ts_node_has_error, (TSNode));
 DEF_DLL_FN (bool, ts_node_is_extra, (TSNode));
 DEF_DLL_FN (bool, ts_node_is_missing, (TSNode));
@@ -174,8 +170,6 @@ init_treesit_functions (void)
   LOAD_DLL_FN (library, ts_node_end_byte);
   LOAD_DLL_FN (library, ts_node_eq);
   LOAD_DLL_FN (library, ts_node_field_name_for_child);
-  LOAD_DLL_FN (library, ts_node_first_child_for_byte);
-  LOAD_DLL_FN (library, ts_node_first_named_child_for_byte);
   LOAD_DLL_FN (library, ts_node_has_error);
   LOAD_DLL_FN (library, ts_node_is_extra);
   LOAD_DLL_FN (library, ts_node_is_missing);
@@ -232,8 +226,6 @@ init_treesit_functions (void)
 #define ts_node_end_byte fn_ts_node_end_byte
 #define ts_node_eq fn_ts_node_eq
 #define ts_node_field_name_for_child fn_ts_node_field_name_for_child
-#define ts_node_first_child_for_byte fn_ts_node_first_child_for_byte
-#define ts_node_first_named_child_for_byte 
fn_ts_node_first_named_child_for_byte
 #define ts_node_has_error fn_ts_node_has_error
 #define ts_node_is_extra fn_ts_node_is_extra
 #define ts_node_is_missing fn_ts_node_is_missing
@@ -2095,6 +2087,41 @@ return nil.  */)
   return make_treesit_node (XTS_NODE (node)->parser, sibling);
 }
 
+/* Our reimplementation of ts_node_first_child_for_byte.  The current
+   implementation of that function has problems (see bug#60127), so
+   before it's fixed upstream, we use our own reimplementation of it.
+   Return true if there is a valid sibling, return false otherwise.
+   If the return value is false, the position of the cursor is
+   undefined.  (We use cursor because technically we can't make a null
+   node for ourselves, also, using cursor is more convenient.)
+
+   TODO: Remove this function once tree-sitter fixed the bug.  */
+static bool treesit_cursor_first_child_for_byte
+(TSTreeCursor *cursor, ptrdiff_t pos, bool named)
+{
+  if (!ts_tree_cursor_goto_first_child (cursor))
+    return false;
+
+  TSNode node = ts_tree_cursor_current_node (cursor);
+  while (ts_node_end_byte (node) <= pos)
+    {
+      if (ts_tree_cursor_goto_next_sibling (cursor))
+       node = ts_tree_cursor_current_node (cursor);
+      else
+       /* Reached the end and still can't find a valid sibling.  */
+       return false;
+    }
+  while (named && (!ts_node_is_named (node)))
+    {
+      if (ts_tree_cursor_goto_next_sibling (cursor))
+       node = ts_tree_cursor_current_node (cursor);
+      else
+       /* Reached the end and still can't find a named sibling.  */
+       return false;
+    }
+  return true;
+}
+
 DEFUN ("treesit-node-first-child-for-pos",
        Ftreesit_node_first_child_for_pos,
        Streesit_node_first_child_for_pos, 2, 3, 0,
@@ -2119,16 +2146,17 @@ Note that this function returns an immediate child, not 
the smallest
 
   ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos));
   TSNode treesit_node = XTS_NODE (node)->node;
-  TSNode child;
-  if (NILP (named))
-    child = ts_node_first_child_for_byte (treesit_node, byte_pos - 
visible_beg);
-  else
-    child = ts_node_first_named_child_for_byte (treesit_node,
-                                               byte_pos - visible_beg);
 
-  if (ts_node_is_null (child))
-    return Qnil;
+  TSTreeCursor cursor = ts_tree_cursor_new (treesit_node);
+  ptrdiff_t treesit_pos = byte_pos - visible_beg;
+  bool success;
+  success = treesit_cursor_first_child_for_byte (&cursor, treesit_pos,
+                                                !NILP (named));
+  TSNode child = ts_tree_cursor_current_node (&cursor);
+  ts_tree_cursor_delete (&cursor);
 
+  if (!success)
+    return Qnil;
   return make_treesit_node (XTS_NODE (node)->parser, child);
 }
 
@@ -3270,9 +3298,9 @@ a regexp.  */)
 
   Lisp_Object parser = XTS_NODE (root)->parser;
   Lisp_Object parent = Fcons (Qnil, Qnil);
-  TSTreeCursor cursor;
-  if (!treesit_cursor_helper (&cursor, XTS_NODE (root)->node, parser))
-    return Qnil;
+  /* In this function we never traverse above NODE, so we don't need
+     to use treesit_cursor_helper.  */
+  TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node);
 
   treesit_build_sparse_tree (&cursor, parent, predicate, process_fn,
                             the_limit, parser);
diff --git a/src/xterm.c b/src/xterm.c
index 1373045393..1325d923be 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -24483,6 +24483,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                    }
                }
 
+#ifndef HAVE_EXT_TOOL_BAR
              /* Now see if the touchpoint was previously on the tool bar.
                 If it was, release the tool bar.  */
 
@@ -24507,6 +24508,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                  /* Now clear the tool bar device.  */
                  FRAME_OUTPUT_DATA (f)->tool_bar_touch_device = 0;
                }
+#endif
 
              goto XI_OTHER;
            }
diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el 
b/test/lisp/erc/erc-scenarios-base-local-modules.el
index d4001df45d..916d105779 100644
--- a/test/lisp/erc/erc-scenarios-base-local-modules.el
+++ b/test/lisp/erc/erc-scenarios-base-local-modules.el
@@ -19,8 +19,17 @@
 
 ;;; Commentary:
 
-;; These tests all use `sasl' because, as of ERC 5.5, it's the one
-;; and only local module.
+;; A local module doubles as a minor mode whose mode variable and
+;; associated local data can withstand service disruptions.
+;; Unfortunately, the current implementation is too unwieldy to be
+;; made public because it doesn't perform any of the boiler plate
+;; needed to save and restore buffer-local and "network-local" copies
+;; of user options.  Ultimately, a user-friendly framework must fill
+;; this void if third-party local modules are ever to become
+;; practical.
+;;
+;; The following tests all use `sasl' because, as of ERC 5.5, it's the
+;; only local module.
 
 ;;; Code:
 
@@ -206,7 +215,7 @@
         (erc-cmd-QUIT "")
         (funcall expect 10 "finished")))
 
-    (ert-info ("Disabling works from a target buffer.")
+    (ert-info ("Disabling works from a target buffer")
       (with-current-buffer "#chan"
         (should erc-sasl-mode)
         (call-interactively #'erc-sasl-disable)
@@ -214,10 +223,9 @@
         (should (local-variable-p 'erc-sasl-mode))
         (should-not (buffer-local-value 'erc-sasl-mode (get-buffer "foonet")))
         (erc-cmd-RECONNECT)
-        (with-current-buffer "#chan"
-          (funcall expect 10 "Some enigma, some riddle")
-          (should-not erc-sasl-mode) ; regression
-          (should (local-variable-p 'erc-sasl-mode))))
+        (funcall expect 10 "Some enigma, some riddle")
+        (should-not erc-sasl-mode) ; regression
+        (should (local-variable-p 'erc-sasl-mode)))
 
       (with-current-buffer "foonet"
         (should (local-variable-p 'erc-sasl-mode))
@@ -239,4 +247,82 @@
         (should erc-sasl-mode)
         (funcall expect 10 "User modes for tester")))))
 
+(defvar-local erc-scenarios-base-local-modules--local-var nil)
+
+(define-erc-module -phony-sblm- nil
+  "Test module for `erc-scenarios-base-local-modules--var-persistence'."
+  ((when-let ((vars (or erc--server-reconnecting erc--target-priors)))
+     (should (assq 'erc--phony-sblm--mode vars))
+     (setq erc-scenarios-base-local-modules--local-var
+           (alist-get 'erc-scenarios-base-local-modules--local-var vars)))
+   (setq erc-scenarios-base-local-modules--local-var
+         (or erc-scenarios-base-local-modules--local-var
+             (if erc--target 100 0))))
+  ((kill-local-variable 'erc-scenarios-base-local-modules--local-var))
+  'local)
+
+;; Note: this file has grown too expensive (time-wise) and must be
+;; split up.  When that happens, this test should be rewritten without
+;; any time-saving hacks, namely, server-initiated JOINs and an
+;; absence of QUITs.  (That said, three connections in under 2 seconds
+;; is pretty nice.)
+
+(ert-deftest erc-scenarios-base-local-modules--var-persistence ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/reconnect")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'options 'options 'options))
+       (port (process-contact dumb-server :service))
+       (erc-modules (cons '-phony-sblm- (remq 'autojoin erc-modules)))
+       (expect (erc-d-t-make-expecter))
+       (server-buffer-name (format "127.0.0.1:%d" port)))
+
+    (ert-info ("Initial authentication succeeds as expected")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "changeme"
+                                :full-name "tester")
+        (should (string= (buffer-name) server-buffer-name)))
+
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "FooNet"))
+        (funcall expect 10 "This server is in debug mode")
+        (should erc--phony-sblm--mode)
+        (should (eql erc-scenarios-base-local-modules--local-var 0))
+        (setq erc-scenarios-base-local-modules--local-var 1)))
+
+    (ert-info ("Save module's local var in target buffer")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (should (eql erc-scenarios-base-local-modules--local-var 100))
+        (setq erc-scenarios-base-local-modules--local-var 101)
+        (funcall expect 20 "welcome")))
+
+    (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
+
+    (ert-info ("Vars reused when mode was left enabled")
+      (with-current-buffer "#chan"
+        (erc-cmd-RECONNECT)
+        (funcall expect 20 "welcome")
+        (should (eql erc-scenarios-base-local-modules--local-var 101))
+        (erc--phony-sblm--mode -1))
+
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "User modes for tester")
+        (should (eql erc-scenarios-base-local-modules--local-var 1))))
+
+    (with-current-buffer "FooNet" (funcall expect 20 "terminated"))
+
+    (ert-info ("Local binding gone when mode disabled in target")
+      (with-current-buffer "#chan"
+        (erc-cmd-RECONNECT)
+        (funcall expect 20 "welcome")
+        (should-not erc--phony-sblm--mode)
+        (should-not erc-scenarios-base-local-modules--local-var))
+
+      ;; But value retained in server buffer, where mode is active.
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "User modes for tester")
+        (should (eql erc-scenarios-base-local-modules--local-var 1))))))
+
 ;;; erc-scenarios-local-modules.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 85506c3d27..40a2d2de65 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1251,18 +1251,28 @@
         (setq calls nil)))))
 
 (ert-deftest erc--merge-local-modes ()
-
-  (ert-info ("No existing modes")
-    (let ((old '((a) (b . t)))
-          (new '(erc-c-mode erc-d-mode)))
-      (should (equal (erc--merge-local-modes new old)
-                     '((erc-c-mode erc-d-mode))))))
-
-  (ert-info ("Active existing added, inactive existing removed, deduped")
-    (let ((old '((a) (erc-b-mode) (c . t) (erc-d-mode . t) (erc-e-mode . t)))
-          (new '(erc-b-mode erc-d-mode)))
-      (should (equal (erc--merge-local-modes new old)
-                     '((erc-d-mode erc-e-mode) . (erc-b-mode)))))))
+  (cl-letf (((get 'erc-b-mode 'erc-module) 'b)
+            ((get 'erc-c-mode 'erc-module) 'c)
+            ((get 'erc-d-mode 'erc-module) 'd)
+            ((get 'erc-e-mode 'erc-module) 'e))
+
+    (ert-info ("No existing modes")
+      (let ((old '((a) (b . t)))
+            (new '(erc-c-mode erc-d-mode)))
+        (should (equal (erc--merge-local-modes new old)
+                       '((erc-c-mode erc-d-mode))))))
+
+    (ert-info ("Active existing added, inactive existing removed, deduped")
+      (let ((old '((a) (erc-b-mode) (c . t) (erc-d-mode . t) (erc-e-mode . t)))
+            (new '(erc-b-mode erc-d-mode)))
+        (should (equal (erc--merge-local-modes new old)
+                       '((erc-d-mode erc-e-mode) . (erc-b-mode))))))
+
+    (ert-info ("Non-module erc-prefixed mode ignored")
+      (let ((old '((erc-b-mode) (erc-f-mode . t) (erc-d-mode . t)))
+            (new '(erc-b-mode)))
+        (should (equal (erc--merge-local-modes new old)
+                       '((erc-d-mode) . (erc-b-mode))))))))
 
 (ert-deftest define-erc-module--global ()
   (let ((global-module '(define-erc-module mname malias
@@ -1300,13 +1310,15 @@ Some docstring"
                         (ignore c) (ignore d))
 
                       (defalias 'erc-malias-mode #'erc-mname-mode)
+                      (put 'erc-malias-mode 'erc-module 'mname)
 
+                      (put 'erc-mname-mode 'erc-module 'mname)
                       (put 'erc-mname-mode 'definition-name 'mname)
                       (put 'erc-mname-enable 'definition-name 'mname)
                       (put 'erc-mname-disable 'definition-name 'mname))))))
 
 (ert-deftest define-erc-module--local ()
-  (let* ((global-module '(define-erc-module mname malias
+  (let* ((global-module '(define-erc-module mname nil ; no alias
                            "Some docstring"
                            ((ignore a) (ignore b))
                            ((ignore c) (ignore d))
@@ -1353,8 +1365,7 @@ When called interactively, do so in all buffers for the 
current connection."
                             (setq erc-mname-mode nil)
                             (ignore c) (ignore d))))
 
-                      (defalias 'erc-malias-mode #'erc-mname-mode)
-
+                      (put 'erc-mname-mode 'erc-module 'mname)
                       (put 'erc-mname-mode 'definition-name 'mname)
                       (put 'erc-mname-enable 'definition-name 'mname)
                       (put 'erc-mname-disable 'definition-name 'mname))))))
diff --git a/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
index e2fe143028..a270c743d9 100644
--- a/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
+++ b/test/lisp/erc/resources/base/netid/bouncer/barnet-again.eld
@@ -1,7 +1,7 @@
 ;; -*- mode: lisp-data; -*-
 ((pass 10 "PASS :barnet:changeme"))
-((nick 3 "NICK tester"))
-((user 3 "USER user 0 * :tester")
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
  (0 ":irc.barnet.org 001 tester :Welcome to the barnet IRC Network tester")
  (0 ":irc.barnet.org 002 tester :Your host is irc.barnet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
  (0 ":irc.barnet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:08 UTC")
@@ -17,7 +17,7 @@
  (0 ":irc.barnet.org 266 tester 3 3 :Current global users 3, max 3")
  (0 ":irc.barnet.org 422 tester :MOTD File is missing"))
 
-((mode-user 10.2 "MODE tester +i")
+((mode-user 10 "MODE tester +i")
  ;; No mode answer ^
 
  (0 ":tester!~u@xrir8fpe4d7ak.irc JOIN #chan")
@@ -36,9 +36,9 @@
  (0 ":irc.znc.in 306 tester :You have been marked as being away")
  (0 ":irc.barnet.org 305 tester :You are no longer marked as being away"))
 
-((~join 3 "JOIN #chan"))
+((~join 10 "JOIN #chan"))
 
-((mode 5 "MODE #chan")
+((mode 10 "MODE #chan")
  (0 ":irc.barnet.org 324 tester #chan +nt")
  (0 ":irc.barnet.org 329 tester #chan 1620805269")
  (0.1 ":joe!~u@svpn88yjcdj42.irc PRIVMSG #chan :mike: But, in defense, by 
mercy, 'tis most just.")
diff --git a/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld 
b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
index bf8712305a..a8c352daaa 100644
--- a/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
+++ b/test/lisp/erc/resources/base/netid/bouncer/foonet-again.eld
@@ -1,7 +1,7 @@
 ;; -*- mode: lisp-data; -*-
 ((pass 10 "PASS :foonet:changeme"))
-((nick 3 "NICK tester"))
-((user 3 "USER user 0 * :tester")
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
  (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
  (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
  (0 ":irc.foonet.org 003 tester :This server was created Wed, 12 May 2021 
07:41:09 UTC")
@@ -17,7 +17,7 @@
  (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
  (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
 
-((mode-user 10.2 "MODE tester +i")
+((mode-user 10 "MODE tester +i")
  ;; No mode answer ^
  (0 ":tester!~u@nvfhxvqm92rm6.irc JOIN #chan")
  (0 ":irc.foonet.org 353 tester = #chan :alice @bob tester")
@@ -36,9 +36,9 @@
  (0 ":irc.foonet.org NOTICE tester :[07:00:32] This server is in debug mode 
and is logging all user I/O. If you do not wish for everything you send to be 
readable by the server owner(s), please disconnect.")
  (0 ":irc.foonet.org 305 tester :You are no longer marked as being away"))
 
-((~join 3 "JOIN #chan"))
+((~join 10 "JOIN #chan"))
 
-((mode 8 "MODE #chan")
+((mode 10 "MODE #chan")
  (0 ":irc.foonet.org 324 tester #chan +nt")
  (0 ":irc.foonet.org 329 tester #chan 1620805271")
  (0.1 ":alice!~u@svpn88yjcdj42.irc PRIVMSG #chan :bob: Grows, lives, and dies, 
in single blessedness.")
diff --git a/test/lisp/eshell/em-prompt-tests.el 
b/test/lisp/eshell/em-prompt-tests.el
index 91464a98c2..db45e2ae3a 100644
--- a/test/lisp/eshell/em-prompt-tests.el
+++ b/test/lisp/eshell/em-prompt-tests.el
@@ -44,7 +44,8 @@
      (should (equal-including-properties
               last-prompt
               (propertize
-               (format "%s $ " (directory-file-name default-directory))
+               (format "%s %s " (directory-file-name default-directory)
+                       (if (= (file-user-uid) 0) "#" "$"))
                'read-only t
                'field 'prompt
                'font-lock-face 'eshell-prompt
@@ -68,7 +69,8 @@ This tests the case when `eshell-highlight-prompt' is nil."
        (should (equal-including-properties
                 last-prompt
                 (propertize
-                 (format "%s $ " (directory-file-name default-directory))
+                 (format "%s %s " (directory-file-name default-directory)
+                         (if (= (file-user-uid) 0) "#" "$"))
                  'field 'prompt
                  'front-sticky '(field)
                  'rear-nonsticky '(field))))
diff --git a/test/lisp/net/tramp-archive-tests.el 
b/test/lisp/net/tramp-archive-tests.el
index 59b7ed9cf7..8fe1dbd8d0 100644
--- a/test/lisp/net/tramp-archive-tests.el
+++ b/test/lisp/net/tramp-archive-tests.el
@@ -878,7 +878,18 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
                 (zerop (nth 1 fsi))
                 (zerop (nth 2 fsi))))))
 
-(ert-deftest tramp-archive-test47-auto-load ()
+;; `file-user-uid' was introduced in Emacs 30.1.
+(ert-deftest tramp-archive-test44-file-user-uid ()
+  "Check that `file-user-uid' returns proper values."
+  (skip-unless tramp-archive-enabled)
+  (skip-unless (fboundp 'file-user-uid))
+
+  (let ((default-directory tramp-archive-test-archive))
+    ;; `file-user-uid' exists since Emacs 30.1.  We don't want to see
+    ;; compiler warnings for older Emacsen.
+    (should (integerp (with-no-warnings (file-user-uid))))))
+
+(ert-deftest tramp-archive-test48-auto-load ()
   "Check that `tramp-archive' autoloads properly."
   :tags '(:expensive-test)
   (skip-unless tramp-archive-enabled)
@@ -923,7 +934,7 @@ This tests also `file-executable-p', `file-writable-p' and 
`set-file-modes'."
               (format "(setq tramp-archive-enabled %s)" enabled))
              (shell-quote-argument (format code file)))))))))))
 
-(ert-deftest tramp-archive-test47-delay-load ()
+(ert-deftest tramp-archive-test48-delay-load ()
   "Check that `tramp-archive' is loaded lazily, only when needed."
   :tags '(:expensive-test)
   (skip-unless tramp-archive-enabled)
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index 168933b6b4..0932a53f4b 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -33,7 +33,7 @@
 ;; remote host, set this environment variable to "/dev/null" or
 ;; whatever is appropriate on your system.
 
-;; For slow remote connections, `tramp-test44-asynchronous-requests'
+;; For slow remote connections, `tramp-test45-asynchronous-requests'
 ;; might be too heavy.  Setting $REMOTE_PARALLEL_PROCESSES to a proper
 ;; value less than 10 could help.
 
@@ -6297,7 +6297,7 @@ INPUT, if non-nil, is a string sent to the process."
   (skip-unless (and (fboundp 'file-locked-p) (fboundp 'make-lock-file-name)))
 
   ;; `lock-file', `unlock-file', `file-locked-p' and
-  ;; `make-lock-file-name' exists since Emacs 28.1.  We don't want to
+  ;; `make-lock-file-name' exist since Emacs 28.1.  We don't want to
   ;; see compiler warnings for older Emacsen.
   (dolist (quoted (if (tramp--test-expensive-test-p) '(nil t) '(nil)))
     (let ((tmp-name1 (tramp--test-make-temp-name nil quoted))
@@ -7076,11 +7076,40 @@ This requires restrictions of file name syntax."
     (dotimes (i (length fsi))
       (should (natnump (or (nth i fsi) 0))))))
 
-;; `tramp-test44-asynchronous-requests' could be blocked.  So we set a
+;; `file-user-uid' was introduced in Emacs 30.1.
+(ert-deftest tramp-test44-file-user-uid ()
+  "Check that `file-user-uid' and `tramp-get-remote-*' return proper values."
+  (skip-unless (tramp--test-enabled))
+
+  (let ((default-directory ert-remote-temporary-file-directory))
+    ;; `file-user-uid' exists since Emacs 30.1.  We don't want to see
+    ;; compiler warnings for older Emacsen.
+    (when (fboundp 'file-user-uid)
+      (should (integerp (with-no-warnings (file-user-uid)))))
+
+    (with-parsed-tramp-file-name default-directory nil
+      (should (or (integerp (tramp-get-remote-uid v 'integer))
+                 (null (tramp-get-remote-uid v 'integer))))
+      (should (or (stringp (tramp-get-remote-uid v 'string))
+                 (null (tramp-get-remote-uid v 'string))))
+
+      (should (or (integerp (tramp-get-remote-gid v 'integer))
+                 (null (tramp-get-remote-gid v 'integer))))
+      (should (or (stringp (tramp-get-remote-gid v 'string))
+                 (null (tramp-get-remote-gid v 'string))))
+
+      (when-let ((groups (tramp-get-remote-groups v 'integer)))
+       (should (consp groups))
+       (dolist (group groups) (should (integerp group))))
+      (when-let ((groups (tramp-get-remote-groups v 'string)))
+       (should (consp groups))
+       (dolist (group groups) (should (stringp group)))))))
+
+;; `tramp-test45-asynchronous-requests' could be blocked.  So we set a
 ;; timeout of 300 seconds, and we send a SIGUSR1 signal after 300
 ;; seconds.  Similar check is performed in the timer function.
 (defconst tramp--test-asynchronous-requests-timeout 300
-  "Timeout for `tramp-test44-asynchronous-requests'.")
+  "Timeout for `tramp-test45-asynchronous-requests'.")
 
 (defmacro tramp--test-with-proper-process-name-and-buffer (proc &rest body)
   "Set \"process-name\" and \"process-buffer\" connection properties.
@@ -7116,7 +7145,7 @@ This is needed in timer functions as well as process 
filters and sentinels."
         (tramp-flush-connection-property v "process-buffer")))))
 
 ;; This test is inspired by Bug#16928.
-(ert-deftest tramp-test44-asynchronous-requests ()
+(ert-deftest tramp-test45-asynchronous-requests ()
   "Check parallel asynchronous requests.
 Such requests could arrive from timers, process filters and
 process sentinels.  They shall not disturb each other."
@@ -7283,7 +7312,7 @@ process sentinels.  They shall not disturb each other."
                   (unless (process-live-p proc)
                     (setq buffers (delq buf buffers))))))
 
-            ;; Checks.  All process output shall exists in the
+            ;; Checks.  All process output shall exist in the
             ;; respective buffers.  All created files shall be
             ;; deleted.
             (tramp--test-message "Check %s" (current-time-string))
@@ -7309,10 +7338,10 @@ process sentinels.  They shall not disturb each other."
         (ignore-errors (cancel-timer timer))
         (ignore-errors (delete-directory tmp-name 'recursive))))))
 
-;; (tramp--test-deftest-direct-async-process tramp-test44-asynchronous-requests
+;; (tramp--test-deftest-direct-async-process tramp-test45-asynchronous-requests
 ;;   'unstable)
 
-(ert-deftest tramp-test45-dired-compress-file ()
+(ert-deftest tramp-test46-dired-compress-file ()
   "Check that Tramp (un)compresses normal files."
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-sh-p))
@@ -7333,7 +7362,7 @@ process sentinels.  They shall not disturb each other."
     (should (string= tmp-name (dired-get-filename)))
     (delete-file tmp-name)))
 
-(ert-deftest tramp-test45-dired-compress-dir ()
+(ert-deftest tramp-test46-dired-compress-dir ()
   "Check that Tramp (un)compresses directories."
   (skip-unless (tramp--test-enabled))
   (skip-unless (tramp--test-sh-p))
@@ -7355,7 +7384,7 @@ process sentinels.  They shall not disturb each other."
     (delete-directory tmp-name)
     (delete-file (concat tmp-name ".tar.gz"))))
 
-(ert-deftest tramp-test46-read-password ()
+(ert-deftest tramp-test47-read-password ()
   "Check Tramp password handling."
   :tags '(:expensive-test)
   (skip-unless (tramp--test-enabled))
@@ -7415,7 +7444,7 @@ process sentinels.  They shall not disturb each other."
            (should (file-exists-p ert-remote-temporary-file-directory)))))))))
 
 ;; This test is inspired by Bug#29163.
-(ert-deftest tramp-test47-auto-load ()
+(ert-deftest tramp-test48-auto-load ()
   "Check that Tramp autoloads properly."
   ;; If we use another syntax but `default', Tramp is already loaded
   ;; due to the `tramp-change-syntax' call.
@@ -7440,7 +7469,7 @@ process sentinels.  They shall not disturb each other."
        (mapconcat #'shell-quote-argument load-path " -L ")
        (shell-quote-argument code)))))))
 
-(ert-deftest tramp-test47-delay-load ()
+(ert-deftest tramp-test48-delay-load ()
   "Check that Tramp is loaded lazily, only when needed."
   ;; Tramp is neither loaded at Emacs startup, nor when completing a
   ;; non-Tramp file name like "/foo".  Completing a Tramp-alike file
@@ -7470,7 +7499,7 @@ process sentinels.  They shall not disturb each other."
          (mapconcat #'shell-quote-argument load-path " -L ")
          (shell-quote-argument (format code tm)))))))))
 
-(ert-deftest tramp-test47-recursive-load ()
+(ert-deftest tramp-test48-recursive-load ()
   "Check that Tramp does not fail due to recursive load."
   (skip-unless (tramp--test-enabled))
 
@@ -7494,7 +7523,7 @@ process sentinels.  They shall not disturb each other."
          (mapconcat #'shell-quote-argument load-path " -L ")
          (shell-quote-argument code))))))))
 
-(ert-deftest tramp-test47-remote-load-path ()
+(ert-deftest tramp-test48-remote-load-path ()
   "Check that Tramp autoloads its packages with remote `load-path'."
   ;; `tramp-cleanup-all-connections' is autoloaded from tramp-cmds.el.
   ;; It shall still work, when a remote file name is in the
@@ -7519,7 +7548,7 @@ process sentinels.  They shall not disturb each other."
        (mapconcat #'shell-quote-argument load-path " -L ")
        (shell-quote-argument code)))))))
 
-(ert-deftest tramp-test48-unload ()
+(ert-deftest tramp-test49-unload ()
   "Check that Tramp and its subpackages unload completely.
 Since it unloads Tramp, it shall be the last test to run."
   :tags '(:expensive-test)
@@ -7620,19 +7649,19 @@ If INTERACTIVE is non-nil, the tests are run 
interactively."
 ;; * file-name-case-insensitive-p
 ;; * memory-info
 ;; * tramp-get-home-directory
-;; * tramp-get-remote-gid
-;; * tramp-get-remote-groups
-;; * tramp-get-remote-uid
 ;; * tramp-set-file-uid-gid
 
 ;; * Work on skipped tests.  Make a comment, when it is impossible.
 ;; * Revisit expensive tests, once problems in `tramp-error' are solved.
 ;; * Fix `tramp-test06-directory-file-name' for "ftp".
+;; * Check, why a process filter t doesn't work in
+;;   `tramp-test29-start-file-process' and
+;;   `tramp-test30-make-process'.
 ;; * Implement `tramp-test31-interrupt-process' and
 ;;   `tramp-test31-signal-process' for "adb", "sshfs" and for direct
 ;;   async processes.  Check, why they don't run stable.
 ;; * Check, why direct async processes do not work for
-;;   `tramp-test44-asynchronous-requests'.
+;;   `tramp-test45-asynchronous-requests'.
 
 (provide 'tramp-tests)
 
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb 
b/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
new file mode 100644
index 0000000000..4be532a5e9
--- /dev/null
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby-ts.rb
@@ -0,0 +1,94 @@
+variable = foo(
+  [
+    qwe
+  ], [
+    rty
+  ], {
+    a: 3
+  }
+)
+
+tee = [
+  qwe
+]
+
+qux = [1,
+       2]
+
+att = {a: 1,
+       b: 2}
+
+a = 1 ? 2 :(
+  2 + 3
+)
+
+unless bismark
+  sink += 12
+else
+  dog = 99
+end
+
+foo1 =
+  subject.update(
+    1
+  )
+
+foo2 =
+  subject.
+    update(
+      # Might make sense to indent this to 'subject' instead; but this
+      # style seems more popular.
+      2
+    )
+
+foo > bar &&
+  tee < qux
+
+1 .. 2 &&
+     3
+
+a = foo(j, k) -
+    bar_tee
+
+qux = foo.fee ?
+        bar :
+        tee
+
+with_paren = (a + b *
+                  c * d +
+              12)
+
+without_paren = a + b *
+                    c * d +
+                12
+
+{'a' => {
+   'b' => 'c',
+   'd' => %w(e f)
+ }
+}
+
+[1, 2, {
+   'b' => 'c',
+   'd' => %w(e f)
+ }
+]
+
+foo(a, {
+      a: b,
+      c: d
+    })
+
+foo(foo, bar:
+    tee)
+
+foo(foo, :bar =>
+    tee)
+
+# Local Variables:
+# mode: ruby-ts
+# ruby-after-operator-indent: t
+# ruby-block-indent: t
+# ruby-method-call-indent: t
+# ruby-method-params-indent: t
+# End:
diff --git a/test/lisp/progmodes/ruby-ts-mode-tests.el 
b/test/lisp/progmodes/ruby-ts-mode-tests.el
index eaf6367a30..d34c235e82 100644
--- a/test/lisp/progmodes/ruby-ts-mode-tests.el
+++ b/test/lisp/progmodes/ruby-ts-mode-tests.el
@@ -250,8 +250,12 @@ The whitespace before and including \"|\" on each line is 
removed."
                (should (equal (buffer-string) orig))))
          (kill-buffer buf)))))
 
-(ruby-ts-deftest-indent "ruby-method-params-indent.rb")
+(ruby-ts-deftest-indent "ruby-ts.rb")
+(ruby-ts-deftest-indent "ruby-after-operator-indent.rb")
 (ruby-ts-deftest-indent "ruby-block-indent.rb")
+(ruby-ts-deftest-indent "ruby-method-call-indent.rb")
+(ruby-ts-deftest-indent "ruby-method-params-indent.rb")
+(ruby-ts-deftest-indent "ruby-parenless-call-arguments-indent.rb")
 
 (provide 'ruby-ts-mode-tests)
 
diff --git a/test/src/buffer-tests.el b/test/src/buffer-tests.el
index e5de8f3464..9d4bbf3e04 100644
--- a/test/src/buffer-tests.el
+++ b/test/src/buffer-tests.el
@@ -8315,29 +8315,35 @@ dicta sunt, explicabo.  "))
       (remove-hook 'buffer-list-update-hook bluh))))
 
 (ert-deftest buffer-tests-inhibit-buffer-hooks-indirect ()
-  "Indirect buffers do not call `get-buffer-create'."
-  (dolist (inhibit '(nil t))
-    (let ((base (get-buffer-create "foo" inhibit)))
+  "Test `make-indirect-buffer' argument INHIBIT-BUFFER-HOOKS."
+  (let* ( base run-bluh run-kbh run-kbqf
+          (bluh (lambda () (setq run-bluh t)))
+          (kbh  (lambda () (setq run-kbh  t)))
+          (kbqf (lambda () (setq run-kbqf t))))
+    (dolist (inhibit-base '(nil t))
       (unwind-protect
-          (dotimes (_i 11)
-            (let* (flag*
-                   (flag (lambda () (prog1 t (setq flag* t))))
-                   (indirect (make-indirect-buffer base "foo[indirect]" nil
-                                                   inhibit)))
-              (unwind-protect
-                  (progn
-                    (with-current-buffer indirect
-                      (add-hook 'kill-buffer-query-functions flag nil t))
-                    (kill-buffer indirect)
-                    (if inhibit
-                        (should-not flag*)
-                      (should flag*)))
-                (let (kill-buffer-query-functions)
+          (let (indirect)
+            (setq base (generate-new-buffer " base" inhibit-base))
+            (dolist (inhibit-indirect '(nil t))
+              (dotimes (_ 11)
+                (unwind-protect
+                    (let ((name (generate-new-buffer-name " indirect")))
+                      (setq run-bluh nil run-kbh nil run-kbqf nil)
+                      (add-hook 'buffer-list-update-hook bluh)
+                      (with-current-buffer
+                          (setq indirect (make-indirect-buffer
+                                          base name nil inhibit-indirect))
+                        (add-hook 'kill-buffer-hook kbh nil t)
+                        (add-hook 'kill-buffer-query-functions kbqf nil t)
+                        (kill-buffer))
+                      (should (xor inhibit-indirect run-bluh))
+                      (should (xor inhibit-indirect run-kbh))
+                      (should (xor inhibit-indirect run-kbqf)))
+                  (remove-hook 'buffer-list-update-hook bluh)
                   (when (buffer-live-p indirect)
                     (kill-buffer indirect))))))
-        (let (kill-buffer-query-functions)
-          (when (buffer-live-p base)
-            (kill-buffer base)))))))
+        (when (buffer-live-p base)
+          (kill-buffer base))))))
 
 (ert-deftest zero-length-overlays-and-not ()
   (with-temp-buffer



reply via email to

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