emacs-diffs
[Top][All Lists]
Advanced

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

scratch/pkg 53c07bd04bf: Merge remote-tracking branch 'origin/master' in


From: Gerd Moellmann
Subject: scratch/pkg 53c07bd04bf: Merge remote-tracking branch 'origin/master' into scratch/pkg
Date: Thu, 24 Aug 2023 05:28:49 -0400 (EDT)

branch: scratch/pkg
commit 53c07bd04bf59f63e49af2c626714bf3fdd03ad6
Merge: 19c2006243a ad5e17d0638
Author: Gerd Möllmann <gerd@gnu.org>
Commit: Gerd Möllmann <gerd@gnu.org>

    Merge remote-tracking branch 'origin/master' into scratch/pkg
---
 .dir-locals.el                                   |   2 +-
 .gitattributes                                   |   4 +
 build-aux/git-hooks/pre-commit                   |   3 +
 doc/emacs/android.texi                           |  40 +--
 doc/emacs/files.texi                             |  12 +-
 doc/emacs/search.texi                            |  25 +-
 doc/emacs/trouble.texi                           |   2 +-
 doc/lispref/commands.texi                        | 127 +++++++---
 doc/lispref/functions.texi                       |   2 +-
 doc/lispref/processes.texi                       |  17 +-
 doc/lispref/variables.texi                       |   4 +-
 doc/misc/cl.texi                                 |  13 +-
 doc/misc/eshell.texi                             |  73 +++++-
 doc/misc/ses.texi                                |  15 +-
 etc/DEBUG                                        |  18 ++
 etc/NEWS                                         |  25 +-
 etc/PROBLEMS                                     |  45 +++-
 java/Makefile.in                                 |   7 +
 java/README                                      |   1 -
 java/org/gnu/emacs/EmacsDesktopNotification.java |   2 +-
 java/org/gnu/emacs/EmacsSdk11Clipboard.java      |  16 +-
 java/res/drawable/emacs_background.xml           |   4 +-
 java/res/drawable/emacs_foreground.xml           |  16 +-
 lisp/arc-mode.el                                 |   8 +-
 lisp/completion.el                               |   8 +-
 lisp/desktop.el                                  |   2 +-
 lisp/emacs-lisp/package-vc.el                    |   9 +-
 lisp/emacs-lisp/subr-x.el                        |   6 +-
 lisp/epa-file.el                                 |   9 +-
 lisp/eshell/em-cmpl.el                           |  23 ++
 lisp/eshell/em-glob.el                           |  22 +-
 lisp/eshell/em-hist.el                           |  27 +-
 lisp/eshell/em-pred.el                           |  29 ++-
 lisp/eshell/esh-io.el                            | 308 ++++++++++++-----------
 lisp/eshell/esh-proc.el                          |  25 +-
 lisp/eshell/esh-var.el                           |  11 +-
 lisp/face-remap.el                               |  13 +-
 lisp/files.el                                    |   6 +-
 lisp/gnus/gnus-search.el                         |   7 +
 lisp/help-fns.el                                 |  11 +-
 lisp/image-mode.el                               |   5 +-
 lisp/image/image-dired.el                        |  36 ++-
 lisp/keymap.el                                   |   4 +-
 lisp/net/ange-ftp.el                             |   2 +-
 lisp/net/tramp-cmds.el                           |   2 +
 lisp/net/tramp-compat.el                         |   2 +-
 lisp/org/org-mouse.el                            |   4 +
 lisp/progmodes/c-ts-mode.el                      | 115 +++++----
 lisp/progmodes/csharp-mode.el                    |   1 +
 lisp/progmodes/js.el                             |  35 +--
 lisp/progmodes/project.el                        | 145 ++++++++---
 lisp/progmodes/vera-mode.el                      |   2 +-
 lisp/progmodes/vhdl-mode.el                      |   2 +-
 lisp/replace.el                                  |  10 +-
 lisp/simple.el                                   |  53 ++--
 lisp/subr.el                                     |   4 +
 lisp/textmodes/bibtex.el                         |   2 +-
 lisp/vc/vc-rcs.el                                |   5 +-
 lisp/window.el                                   |  23 +-
 src/androidterm.c                                |  45 ++--
 src/callproc.c                                   |  11 +
 src/dispnew.c                                    |   1 +
 src/fns.c                                        |   3 +-
 src/font.c                                       |   6 +-
 src/frame.c                                      |   2 +-
 src/haiku_support.cc                             |   4 +-
 src/search.c                                     |   4 +-
 src/sfnt.c                                       | 133 ++++++----
 src/sfnt.h                                       |   3 +
 src/sfntfont.c                                   |  79 +++++-
 src/treesit.c                                    |   4 +
 src/w32term.c                                    |   2 +-
 test/lisp/cus-edit-tests.el                      |   1 -
 test/lisp/eshell/em-glob-tests.el                |  64 +++++
 test/lisp/eshell/em-hist-tests.el                |  43 +++-
 test/lisp/eshell/esh-io-tests.el                 |  10 +
 test/lisp/eshell/esh-var-tests.el                |  46 ++++
 77 files changed, 1290 insertions(+), 620 deletions(-)

diff --git a/.dir-locals.el b/.dir-locals.el
index f0f12db6717..e087aa89cd1 100644
--- a/.dir-locals.el
+++ b/.dir-locals.el
@@ -12,7 +12,7 @@
  (c-mode . ((c-file-style . "GNU")
             (c-noise-macro-names . ("INLINE" "NO_INLINE" 
"ATTRIBUTE_NO_SANITIZE_UNDEFINED"
                                     "UNINIT" "CALLBACK" "ALIGN_STACK" 
"ATTRIBUTE_MALLOC"
-                                    "ATTRIBUTE_DEALLOC_FREE" "ANDROID_EXPORT"))
+                                    "ATTRIBUTE_DEALLOC_FREE" "ANDROID_EXPORT" 
"TEST_STATIC"))
             (electric-quote-comment . nil)
             (electric-quote-string . nil)
             (indent-tabs-mode . t)
diff --git a/.gitattributes b/.gitattributes
index b56f0ec617d..39a82cc0efc 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -116,3 +116,7 @@ build-aux/msys-to-w32 diff=shell
 build-aux/update-subdirs diff=shell
 lib-src/rcs2log diff=shell
 /make-dist diff=shell
+
+# This file contains in-line diffs, which can include trailing
+# whitespace.
+java/INSTALL -whitespace
diff --git a/build-aux/git-hooks/pre-commit b/build-aux/git-hooks/pre-commit
index 12b08d2c25f..2e0dd7dfd7c 100755
--- a/build-aux/git-hooks/pre-commit
+++ b/build-aux/git-hooks/pre-commit
@@ -60,6 +60,9 @@ while IFS= read -r new_name; do
     -* | */-*)
       echo "$new_name: File name component begins with '-'."
       exit 1;;
+    ChangeLog.android)
+      # This file is explicitly ok.
+      ;;
     ChangeLog | */ChangeLog)
       echo "$new_name: Please use git commit messages, not ChangeLog files."
       exit 1;;
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index a85589f864c..5e7ff0e4bb3 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -335,17 +335,17 @@ applications.}
   Each application is also prohibited from accessing many system
 directories and the app data directories of other applications.
 
-  Emacs comes with several binaries.  While being executable files,
-they are packaged as libraries in the library directory, because
-otherwise the system will not unpack them while Emacs is being
-installed.  This means, instead of specifying @code{ctags} or
-@code{emacsclient} in a subprocess, Lisp code must specify
-@code{libctags.so} or @code{libemacsclient.so} on the command line
-instead when starting either of those programs in a subprocess; to
-determine which names to use, consult the values of the variables
-@code{ctags-program-name}, @code{etags-program-name},
-@code{hexl-program-name}, @code{emacsclient-program-name},
-@code{movemail-program-name}, and @code{ebrowse-program-name}.
+  The Emacs distribution also incorporates several binaries.  While
+being executable files, they are packaged as libraries in the library
+directory, because otherwise the system will not unpack them while
+Emacs is being installed.  This means that instead of @code{ctags} or
+@code{emacsclient}, Lisp code must specify @code{libctags.so} or
+@code{libemacsclient.so} on the command line when starting either of
+those programs in a subprocess; to determine which names to use,
+consult the values of the variables @code{ctags-program-name},
+@code{etags-program-name}, @code{hexl-program-name},
+@code{emacsclient-program-name}, @code{movemail-program-name},
+@code{ebrowse-program-name}, and @code{rcs2log-program-name}.
 @xref{Subprocess Creation,,, elisp, the Emacs Lisp Reference Manual}.
 
   The @file{/assets} directory containing Emacs start-up files is
@@ -692,18 +692,20 @@ always be Droid Sans Mono.
 @cindex TrueType GX fonts, android
 @cindex distortable fonts, android
 
-  Like on X systems, Emacs supports distortable fonts under Android.
+  As on X systems, Emacs supports distortable fonts under Android.
 These fonts (also termed ``TrueType GX fonts'', ``variable fonts'',
 and ``multiple master fonts'') provide multiple different styles
 (``Bold'', ``Italic'', etc) using a single font file.
 
-  When a user-installed distortable font is found, each font that a
+  When a user-installed distortable font is found, each style that a
 previously discovered font provided will no longer be used.  In
-addition, any previously specified distortable fonts with the same
-family name are also removed.  When a conventional font is found, any
-previous conventional font with the same style and family will be
-removed; distortable fonts with the same family will no longer be used
-to provide that style.
+addition, any previously installed distortable fonts with the same
+family name are also disregarded, provided that the new distortable
+font supplies a superset of the styles furnished by the previously
+installed font.  When a conventional font is found, any previous
+conventional font with the same style and family will be removed;
+distortable fonts with the same family will no longer be used to
+provide that style.
 
 @node Android Troubleshooting
 @section Troubleshooting Startup Problems on Android
@@ -778,7 +780,7 @@ normally installed from within a purpose-built terminal 
emulator
 application, but Emacs can access them if it is built with the same
 application signing key as the Termux terminal emulator, and with its
 ``shared user ID'' set to the package name of the terminal emulator
-program.  The @file{java/INSTALL} within the Emacs distribution
+program.  The file @file{java/INSTALL} within the Emacs distribution
 explains how to build Emacs in this fashion.
 
   @uref{https://github.com/termux/termux-packages, termux-packages}
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index ac7751ceb53..7efb4516d15 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -372,12 +372,12 @@ you could say:
       '(("src/emacs/[^/]+/\\(.*\\)\\'" "src/emacs/.*/\\1")))
 @end lisp
 
-As you can see, this is a list of @var{(MATCH EXPANSION...)} elements.
-The @var{match} is a regular expression that matches the visited file
-name, and each @var{expansion} may refer to match groups by using
-@samp{\\1} and so on.  The resulting expansion string is then applied
-to the file system to see if any files match this expansion
-(interpreted as a regexp).
+As you can see, this is a list of @w{@code{(@var{MATCH}
+@var{EXPANSION}...)}} elements.  The @var{match} is a regular
+expression that matches the visited file name, and each
+@var{expansion} may refer to match groups by using @samp{\\1} and so
+on.  The resulting expansion string is then applied to the file system
+to see if any files match this expansion (interpreted as a regexp).
 
 @vindex find-file-hook
 @vindex find-file-not-found-functions
diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi
index e8e79888ed8..6d8b3a2727a 100644
--- a/doc/emacs/search.texi
+++ b/doc/emacs/search.texi
@@ -1659,6 +1659,7 @@ command's first argument.  If @code{case-fold-search} is 
set to
 @code{nil}, case is always significant in all searches.
 
 @vindex case-replace
+@cindex case preservation in replace commands
   In addition, when the second argument of a replace command is all or
 partly lower case, replacement commands try to preserve the case
 pattern of each occurrence.  Thus, the command
@@ -1672,7 +1673,27 @@ replaces a lower case @samp{foo} with a lower case 
@samp{bar}, an
 all-caps @samp{FOO} with @samp{BAR}, and a capitalized @samp{Foo} with
 @samp{Bar}.  (These three alternatives---lower case, all caps, and
 capitalized, are the only ones that @code{replace-string} can
-distinguish.)
+distinguish.)  Note that Emacs decides whether to up-case or capitalize
+the replacement text by analyzing each word in the text being
+replaced, and will preserve the letter-case of the replaced text only
+if @emph{all} of its words use the same letter-case.  Thus, the
+command
+
+@example
+M-x replace-string @key{RET} foo bar @key{RET} baz quux @key{RET}
+@end example
+
+@noindent
+replaces @samp{Foo Bar} with @samp{Baz Quux} because both words in
+@samp{Foo Bar} are capitalized.  By contrast, the same command
+replaces @samp{Foo bar} with @samp{baz quux}, i.e.@: it leaves the
+letter-case of the replacement text unchanged, since the two words in
+@samp{Foo bar} use different capitalization.  What exactly is
+considered a ``word'' depends on the syntax tables that are in effect
+in the current buffer (@pxref{Syntax Tables,,, elisp, The Emacs Lisp
+Reference Manual}); thus, @samp{Foo_Bar} is two words in Text mode,
+but could be a single word in some major mode that supports a
+programming language.
 
   If upper-case letters are used in the replacement string, they remain
 upper case every time that text is inserted.  If upper-case letters are
@@ -1709,7 +1730,7 @@ This command finds occurrences of @samp{foo} one by one, 
displays each
 occurrence and asks you whether to replace it.  Aside from querying,
 @code{query-replace} works just like @code{replace-string}
 (@pxref{Unconditional Replace}).  In particular, it preserves case
-provided @code{case-replace} is non-@code{nil}, as it normally is
+provided that @code{case-replace} is non-@code{nil}, as it normally is
 (@pxref{Replacement and Lax Matches}).  A numeric argument means to
 consider only occurrences that are bounded by word-delimiter
 characters.  A negative prefix argument replaces backward.
diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi
index d2e8ac3452a..3a43203619b 100644
--- a/doc/emacs/trouble.texi
+++ b/doc/emacs/trouble.texi
@@ -1514,7 +1514,7 @@ Appendix, elisp, Emacs Lisp Reference}.
 @end ifclear
 
 @item
-Avoid using @code{defadvice} or @code{with-eval-after-load} for Lisp code
+Avoid using @code{advice-add} or @code{with-eval-after-load} for Lisp code
 to be included in Emacs.
 
 @item
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 741d98655d0..78fc43d0daf 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -710,29 +710,77 @@ context.
 @node Generic Commands
 @subsection Select among Command Alternatives
 @cindex generic commands
-@cindex alternatives, defining
-
-The macro @code{define-alternatives} can be used to define
-@dfn{generic commands}.  These are interactive functions whose
-implementation can be selected from several alternatives, as a matter
-of user preference.
+@cindex alternative commands, defining
+
+Sometimes it is useful to define a command that serves as a ``generic
+dispatcher'' capable of invoking one of a set of commands according to
+the user's needs.  For example, imagine that you want to define a
+command named @samp{open} that can ``open'' and display several
+different types of objects.  Or you could have a command named
+@samp{mua} (which stands for Mail User Agent) that can read and send
+email using one of several email backends, such as Rmail, Gnus, or
+MH-E.  The macro @code{define-alternatives} can be used to define such
+@dfn{generic commands}.  A generic command is an interactive function
+whose implementation can be selected from several alternatives, as a
+matter of user preference.
 
 @defmac define-alternatives command &rest customizations
-Define the new command @var{command}, a symbol.
+This macro defines the new generic @var{command}, which can have
+several alternative implementations.  The argument @var{command}
+should be an unquoted symbol.
+
+When invoked, the macro creates an interactive Lisp closure
+(@pxref{Closures}).  When the user runs @w{@kbd{M-x @var{command}
+@key{RET}}} for the first time, Emacs asks to select one of the
+alternative implementations of @var{command}, offering completion for
+the names of these alternatives.  These names come from the user
+option whose name is @code{@var{command}-alternatives}, which the
+macro creates (if it didn't exist before).  To be useful, this
+variable's value should be an alist whose elements have the form
+@w{@code{(@var{alt-name} . @var{alt-func})}}, where @var{alt-name} is
+the name of the alternative and @var{alt-func} is the interactive
+function to be called if this alternative is selected.  When the user
+selects an alternative, Emacs remembers the selection, and will
+thereafter automatically call that selected alternative without
+prompting when the user invokes @kbd{M-x @var{command}} again.  To
+choose a different alternative, type @w{@kbd{C-u M-x @var{command}
+@key{RET}}}--then Emacs will again prompt for one of the alternatives,
+and the selection will override the previous one.
+
+The variable @code{@var{command}-alternatives} can be created before
+calling @code{define-alternatives}, with the appropriate values;
+otherwise the macro creates the variable with a @code{nil} value, and
+it should then be populated with the associations describing the
+alternatives.  Packages that wish to provide their own implementation
+of an existing generic command can use @code{autoload} cookies
+(@pxref{Autoload}) to add to the alist, for example:
+
+@lisp
+;;;###autoload (push '("My name" . my-foo-symbol) foo-alternatives
+@end lisp
+
+If the optional argument @var{customizations} is non-@code{nil}, it
+should consist of alternating @code{defcustom} keywords (typically
+@code{:group} and @code{:version}) and values to add to the definition
+of the @code{defcustom} @code{@var{command}-alternatives}.
 
-When a user runs @kbd{M-x @var{command} @key{RET}} for the first time,
-Emacs prompts for which real form of the command to use, and records
-the selection by way of a custom variable.  Using a prefix argument
-repeats this process of choosing an alternative.
+Here is an example of a simple generic dispatcher command named
+@code{open} with 3 alternative implementations:
 
-The variable @code{@var{command}-alternatives} should contain an alist
-with alternative implementations of @var{command}.
-Until this variable is set, @code{define-alternatives} has no effect.
+@example
+@group
+(define-alternatives open
+  :group 'files
+  :version "42.1")
+@end group
+@group
+(setq open-alternatives
+      '(("file" . find-file)
+       ("directory" . dired)
+       ("hexl" . hexl-find-file)))
+@end group
+@end example
 
-If @var{customizations} is non-@code{nil}, it should consist of
-alternating @code{defcustom} keywords (typically @code{:group} and
-@code{:version}) and values to add to the declaration of
-@code{@var{command}-alternatives}.
 @end defmac
 
 @node Interactive Call
@@ -2433,35 +2481,48 @@ mouse cursor when the finger moved off the mouse wheel.
 @cindex @code{wheel-down} event
 @item (wheel-up @var{position} @var{clicks} @var{lines} @var{pixel-delta})
 @itemx (wheel-down @var{position} @var{clicks} @var{lines} @var{pixel-delta})
-These kinds of event are generated by moving a mouse wheel.  The
+These events are generated by moving a mouse wheel.  The
 @var{position} element is a mouse position list (@pxref{Click
 Events}), specifying the position of the mouse cursor when the event
 occurred.
 
+@vindex mwheel-coalesce-scroll-events
 @var{clicks}, if present, is the number of times that the wheel was
 moved in quick succession.  @xref{Repeat Events}.  @var{lines}, if
-present and not @code{nil}, is the number of screen lines that should
-be scrolled.  @var{pixel-delta}, if present, is a cons cell of the
-form @w{@code{(@var{x} . @var{y})}}, where @var{x} and @var{y} are the
-numbers of pixels by which to scroll in each axis, a.k.a.@:
-@dfn{pixelwise deltas}.
+present and not @code{nil}, is the positive number of screen lines
+that should be scrolled (either up, when the event is @code{wheel-up},
+or down when the event is @code{wheel-down}).  @var{pixel-delta}, if
+present, is a cons cell of the form @w{@code{(@var{x} . @var{y})}},
+where @var{x} and @var{y} are the numbers of pixels by which to scroll
+in each axis, a.k.a.@: @dfn{pixelwise deltas}.  Usually, only one of
+the two will be non-zero, the other will be either zero or very close
+to zero; the larger number indicates the axis to scroll the window.
+When the variable @code{mwheel-coalesce-scroll-events} is @code{nil},
+the scroll commands ignore the @var{lines} element, even if it's
+non-@code{nil}, and use the @var{pixel-delta} data instead; in that
+case, the direction of scrolling is determined by the sign of the
+pixelwise deltas, and the direction (up or down) implied by the event
+kind is ignored.
 
 @cindex pixel-resolution wheel events
 You can use these @var{x} and @var{y} pixelwise deltas to determine
 how much the mouse wheel has actually moved at pixel resolution.  For
 example, the pixelwise deltas could be used to scroll the display at
 pixel resolution, exactly according to the user's turning the mouse
-wheel.
+wheel.  This pixelwise scrolling is possible only when
+@code{mwheel-coalesce-scroll-events} is @code{nil}, and in general the
+@var{pixel-delta} data is not generated when that variable is
+non-@code{nil}.
 
 @vindex mouse-wheel-up-event
 @vindex mouse-wheel-down-event
-This kind of event is generated only on some kinds of systems.  On
-some systems, @code{mouse-4} and @code{mouse-5} are used instead.  For
-portable code, use the variables @code{mouse-wheel-up-event},
-@code{mouse-wheel-up-alternate-event}, @code{mouse-wheel-down-event}
-and @code{mouse-wheel-down-alternate-event} defined in
-@file{mwheel.el} to determine what event types to expect for the mouse
-wheel.
+The @code{wheel-up} and @code{wheel-down} events are generated only on
+some kinds of systems.  On other systems, @code{mouse-4} and
+@code{mouse-5} are used instead.  For portable code, use the variables
+@code{mouse-wheel-up-event}, @code{mouse-wheel-up-alternate-event},
+@code{mouse-wheel-down-event} and
+@code{mouse-wheel-down-alternate-event} defined in @file{mwheel.el} to
+determine what event types to expect from the mouse wheel.
 
 @vindex mouse-wheel-left-event
 @vindex mouse-wheel-right-event
@@ -3223,7 +3284,7 @@ one key sequence.
 The argument @var{disable-text-conversion}, if non-@code{nil}, means
 that system input methods will not directly perform edits to buffer
 text while this key sequence is being read; user input will always
-generated individual key events instead.  @xref{Misc Events} for more
+generated individual key events instead.  @xref{Misc Events}, for more
 about text conversion.
 
 In the following example, Emacs displays the prompt @samp{?} in the
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index af116f62973..53525e6b386 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -2177,7 +2177,7 @@ More specifically, the composition of the two functions 
behaves like:
 @findex defadvice
 @findex ad-activate
 
-A lot of code uses the old @code{defadvice} mechanism, which is largely made
+A lot of code uses the old @code{defadvice} mechanism, which has been made
 obsolete by the new @code{advice-add}, whose implementation and semantics is
 significantly simpler.
 
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index adab9eb0d0c..e055d043c91 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -191,17 +191,18 @@ the function returns just the value of the variable 
@code{exec-path}.
 @vindex hexl-program-name
 @vindex emacsclient-program-name
 @vindex movemail-program-name
-@vindex ebrowse-program-manem
-  When starting a program that is part of the Emacs distribution,
-you must take into account that the program may have been renamed in
-order to comply with executable naming restrictions present on the
-system.
+@vindex ebrowse-program-name
+@vindex rcs2log-program-name
+  When starting a program that is part of the Emacs distribution, you
+must take into account that the program may have been renamed in order
+to comply with executable naming restrictions present on the system.
 
   Instead of starting @command{ctags}, for example, you should specify
 the value of @code{ctags-program-name} instead.  Likewise, instead of
 starting @command{movemail}, you must start
 @code{movemail-program-name}, and the same goes for @command{etags},
-@command{hexl}, @command{emacsclient}, and @command{ebrowse}.
+@command{hexl}, @command{emacsclient}, @code{rcs2log}, and
+@command{ebrowse}.
 
 @node Shell Arguments
 @section Shell Arguments
@@ -1775,7 +1776,7 @@ program was running when the filter function was started. 
 However, if
 This makes it possible to use the Lisp debugger to debug filter
 functions.  @xref{Debugger}.  If an error is caught, Emacs pauses for
 @code{process-error-pause-time} seconds so that the user sees the
-error.  @xref{Asynchronous Processes}
+error.  @xref{Asynchronous Processes}.
 
   Many filter functions sometimes (or always) insert the output in the
 process's buffer, mimicking the actions of the default filter.
@@ -2181,7 +2182,7 @@ programs was running when the sentinel was started.  
However, if
 This makes it possible to use the Lisp debugger to debug the
 sentinel.  @xref{Debugger}.  If an error is caught, Emacs pauses for
 @code{process-error-pause-time} seconds so that the user sees the
-error.  @xref{Asynchronous Processes}
+error.  @xref{Asynchronous Processes}.
 
   While a sentinel is running, the process sentinel is temporarily
 set to @code{nil} so that the sentinel won't run recursively.
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 55761ff75e2..93930d17587 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -351,8 +351,8 @@ A function call is in the tail position if it's the very 
last thing
 done so that the value returned by the call is the value of @var{body}
 itself, as is the case in the recursive call to @code{sum} above.
 
-@strong{Warning:} @code{named-let} works as expected only when
-lexical-binding is enabled.  @xref{Lexical Binding}.
+@code{named-let} can only be used when lexical-binding is enabled.
+@xref{Lexical Binding}.
 @end defspec
 
   Here is a complete list of the other facilities that create local
diff --git a/doc/misc/cl.texi b/doc/misc/cl.texi
index 0284554ed9e..5de33350f4f 100644
--- a/doc/misc/cl.texi
+++ b/doc/misc/cl.texi
@@ -1238,10 +1238,15 @@ of variables.
 
 @defmac cl-flet (bindings@dots{}) forms@dots{}
 This form establishes @code{let}-style bindings for functions rather
-than values.  Each @var{binding} must be a list of the form
-@samp{(@var{name} @var{arglist} @var{body}@dots{})}.  Within
-@var{forms}, any reference to the function @var{name} uses the local
-definition instead of the global one.
+than values.  Each @var{binding} must be a list of one of two forms:
+either @w{@code{(@var{name} @var{expr})}} or @w{@code{(@var{name}
+@var{arglist} @var{body}@dots{})}}.  The @var{name} is the name of the
+function, @var{expr} is an expression which returns the function value
+to which the corresponding @var{name} should be bound, and
+@var{arglist} and @var{body} are the argument list and the body of the
+function to bind to @var{name}.  Within @var{forms}, any reference to
+the function @var{name} uses the local definition provided by
+@var{bindings} instead of the global one.
 
 A ``reference'' to a function name is either a call to that function,
 or a use of its name quoted by @code{function} to be passed on to,
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index 6890728a81d..f8f60bae13a 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -4,7 +4,7 @@
 @settitle Eshell: The Emacs Shell
 @include docstyle.texi
 @defindex cm
-@synindex vr fn
+@syncodeindex vr fn
 @c %**end of header
 
 @copying
@@ -141,7 +141,7 @@ computer frequently enough, it is more than worthwhile in 
the long run.
 Any tool you use often deserves the time spent learning to master it.
 @footnote{For the understandably curious, here is what that command
 looks like: But don't let it fool you; once you know what's going on,
-it's easier than it looks: @code{ls -lt **/*.doc(Lk+50aM+5)}.}
+it's easier than it looks: @code{ls -lt **/*.doc(Lk+100aM+6)}.}
 
 @menu
 * Contributors to Eshell::      People who have helped out!
@@ -317,9 +317,10 @@ specify an argument of some other data type, you can use a 
Lisp form
 (1 2 3)
 @end example
 
-Additionally, many built-in Eshell commands (@pxref{Built-ins}) will
-flatten the arguments they receive, so passing a list as an argument
-will ``spread'' the elements into multiple arguments:
+When calling external commands (and many built-in Eshell commands,
+too) Eshell will flatten the arguments the command receives, so
+passing a list as an argument will ``spread'' the elements into
+multiple arguments:
 
 @example
 ~ $ printnl (list 1 2) 3
@@ -457,6 +458,7 @@ overwriting files.  If both settings are non-@code{nil}, 
the commands
 always prompt.  If both settings are @code{nil} (the default), the
 commands signal an error.
 
+@vindex eshell-default-target-is-dot
 Several commands observe the value of
 @code{eshell-default-target-is-dot}.  If non-@code{nil}, then the
 default target for the commands @command{cp}, @command{mv}, and
@@ -520,6 +522,8 @@ directory.
 With @kbd{cd -42}, you can access the directory stack slots by number.
 
 @item
+@vindex eshell-cd-shows-directory
+@vindex eshell-list-files-after-cd
 If @code{eshell-cd-shows-directory} is non-@code{nil}, @command{cd}
 will report the directory it changes to.  If
 @code{eshell-list-files-after-cd} is non-@code{nil}, then @command{ls}
@@ -554,6 +558,8 @@ $*'}.
 Copy a file to a new location or copy multiple files to the same
 directory.
 
+@vindex eshell-cp-overwrite-files
+@vindex eshell-cp-interactive-query
 If @code{eshell-cp-overwrite-files} is non-@code{nil}, then
 @command{cp} will overwrite files without warning.  If
 @code{eshell-cp-interactive-query} is non-@code{nil}, then
@@ -571,6 +577,7 @@ Compare files using Emacs's internal @code{diff} (not to be 
confused
 with @code{ediff}).  @xref{Comparing Files, , , emacs, The GNU Emacs
 Manual}.
 
+@vindex eshell-plain-diff-behavior
 If @code{eshell-plain-diff-behavior} is non-@code{nil}, then this
 command does not use Emacs's internal @code{diff}.  This is the same
 as using @samp{alias diff '*diff $@@*'}.
@@ -598,6 +605,7 @@ Echoes its input.  By default, this prints in a 
Lisp-friendly fashion
 prints a list of all the arguments; otherwise, it prints the empty
 string.
 
+@vindex eshell-plain-echo-behavior
 If @code{eshell-plain-echo-behavior} is non-@code{nil}, @command{echo}
 will try to behave more like a plain shell's @command{echo}, printing
 each argument as a string, separated by a space.
@@ -618,6 +626,7 @@ cmd*}.
 
 @item exit
 @cmindex exit
+@vindex eshell-kill-on-exit
 Exit Eshell and save the history.  By default, this command kills the
 Eshell buffer, but if @code{eshell-kill-on-exit} is @code{nil}, then
 the buffer is merely buried instead.
@@ -643,6 +652,7 @@ The @command{grep} commands are compatible with GNU 
@command{grep},
 but use Emacs's internal @code{grep} instead.
 @xref{Grep Searching, , , emacs, The GNU Emacs Manual}.
 
+@vindex eshell-plain-grep-behavior
 If @code{eshell-plain-grep-behavior} is non-@code{nil}, then these
 commands do not use Emacs's internal @code{grep}.  This is the same as
 using @samp{alias grep '*grep $@@*'}, though this setting applies to
@@ -681,6 +691,8 @@ and @code{("foo" "bar")} both evaluate to @code{("foo" 
"bar")}.
 @cmindex ln
 Create links to files.
 
+@vindex eshell-ln-overwrite-files
+@vindex eshell-ln-interactive-query
 If @code{eshell-ln-overwrite-files} is non-@code{nil}, @command{ln}
 will overwrite files without warning.  If
 @code{eshell-ln-interactive-query} is non-@code{nil}, then
@@ -692,6 +704,7 @@ Alias to Emacs's @code{locate} function, which simply runs 
the external
 @command{locate} command and parses the results.
 @xref{Dired and Find, , , emacs, The GNU Emacs Manual}.
 
+@vindex eshell-plain-locate-behavior
 If @code{eshell-plain-locate-behavior} is non-@code{nil}, then Emacs's
 internal @code{locate} is not used.  This is the same as using
 @samp{alias locate '*locate $@@*'}.
@@ -700,21 +713,25 @@ internal @code{locate} is not used.  This is the same as 
using
 @cmindex ls
 Lists the contents of directories.
 
+@vindex eshell-ls-use-colors
 If @code{eshell-ls-use-colors} is non-@code{nil}, the contents of a
 directory is color-coded according to file type and status.  These
 colors and the regexps used to identify their corresponding files can
 be customized via @w{@kbd{M-x customize-group @key{RET} eshell-ls @key{RET}}}.
 
+@vindex eshell-ls-date-format
 The user option @code{eshell-ls-date-format} determines how the date
 is displayed when using the @option{-l} option.  The date is produced
 using the function @code{format-time-string} (@pxref{Time Parsing,,,
 elisp, GNU Emacs Lisp Reference Manual}).
 
+@vindex eshell-ls-initial-args
 The user option @code{eshell-ls-initial-args} contains a list of
 arguments to include with any call to @command{ls}.  For example, you
 can include the option @option{-h} to always use a more human-readable
 format.
 
+@vindex eshell-ls-default-blocksize
 The user option @code{eshell-ls-default-blocksize} determines the
 default blocksize used when displaying file sizes with the option
 @option{-s}.
@@ -738,6 +755,8 @@ Make new directories.
 @cmindex mv
 Move or rename files.
 
+@vindex eshell-mv-overwrite-files
+@vindex eshell-mv-interactive-query
 If @code{eshell-mv-overwrite-files} is non-@code{nil}, @command{mv}
 will overwrite files without warning.  If
 @code{eshell-mv-interactive-query} is non-@code{nil}, @command{mv}
@@ -762,6 +781,8 @@ Print the arguments separated by newlines.
 Push the current directory onto the directory stack, then change to
 another directory.
 
+@vindex eshell-pushd-dunique
+@vindex eshell-pushd-dextract
 If @code{eshell-pushd-dunique} is non-@code{nil}, then only unique
 directories will be added to the stack.  If
 @code{eshell-pushd-dextract} is non-@code{nil}, then @samp{pushd
@@ -776,6 +797,8 @@ Prints the current working directory.
 Removes files, buffers, processes, or Emacs Lisp symbols, depending on
 the argument.
 
+@vindex eshell-rm-interactive-query
+@vindex eshell-rm-removes-directories
 If @code{eshell-rm-interactive-query} is non-@code{nil}, @command{rm}
 will prompt before removing anything.  If
 @code{eshell-rm-removes-directories} is non-@code{nil}, then
@@ -1071,6 +1094,13 @@ necessary.  By default, its value is
 @code{@var{emacs-version},eshell}.  Other parts of Emacs, such as
 Tramp, may add extra information to this value.
 
+@vindex $PAGER
+@item $PAGER
+This variable indicates the pager that commands should use when they
+wish to paginate long output.  Its value is that of
+@code{comint-pager} if non-@code{nil}; otherwise, it uses the value of
+@code{$PAGER} from the @code{process-environment}.
+
 @end table
 
 @xref{Aliases}, for the built-in variables @samp{$*}, @samp{$1},
@@ -1080,6 +1110,7 @@ Tramp, may add extra information to this value.
 @section Aliases
 
 @findex eshell-read-aliases-list
+@vindex eshell-aliases-file
 Aliases are commands that expand to a longer input line.  For example,
 @command{ll} is a common alias for @code{ls -l}.  To define this alias
 in Eshell, you can use the command invocation @kbd{alias ll 'ls -l
@@ -1160,6 +1191,7 @@ the option @code{eshell-explicit-remote-commands} to 
@code{nil}.
 @node History
 @section History
 @cmindex history
+@vindex eshell-history-size
 The @samp{history} command shows all commands kept in the history ring
 as numbered list.  If the history ring contains
 @code{eshell-history-size} commands, those numbers change after every
@@ -1179,6 +1211,7 @@ command beginning with @code{foo}, and @samp{!?foo} to 
the last
 command containing @code{foo}.  The n-th argument of the last command
 beginning with @code{foo} is accessible by @code{!foo:n}.
 
+@vindex eshell-history-file-name
 The history ring is loaded from a file at the start of every session,
 and written back to the file at the end of every session.  The file path
 is specified in @code{eshell-history-file-name}.  Unlike other shells,
@@ -1364,6 +1397,7 @@ to @code{$(@var{lisp})}, this is identical to 
@code{@{@var{command}@}}
 when on its own, but the @code{$} allows it to be used inside double
 quotes or as part of a string.
 
+@vindex eshell-convert-numeric-arguments
 Normally, the output is split line-by-line, returning a list (or the
 first element if there's only one line of output); if
 @code{eshell-convert-numeric-arguments} is non-@code{nil} and every
@@ -1466,18 +1500,28 @@ other arguments around it.  For example, if 
@var{numbers} is the list
 
 @node Globbing
 @section Globbing
-@vindex eshell-glob-case-insensitive
 Eshell's globbing syntax is very similar to that of Zsh
 (@pxref{Filename Generation, , , zsh, The Z Shell Manual}).  Users
 coming from Bash can still use Bash-style globbing, as there are no
 incompatibilities.
 
-By default, globs are case sensitive, except on MS-DOS/MS-Windows
+@vindex eshell-glob-case-insensitive
+Globs are case sensitive by default, except on MS-DOS/MS-Windows
 systems.  You can control this behavior via the
-@code{eshell-glob-case-insensitive} option.  You can further customize
-the syntax and behavior of globbing in Eshell via the Customize group
-@code{eshell-glob} (@pxref{Easy Customization, , , emacs, The GNU
-Emacs Manual}).
+@code{eshell-glob-case-insensitive} option.
+
+@vindex eshell-glob-splice-results
+By default, Eshell expands the results of a glob as a sublist into the
+list of arguments.  You can change this to splice the results in-place
+by setting @code{eshell-glob-splice-results} to a non-@code{nil}
+value.  If you want to splice a glob in-place for just one use, you
+can use a subcommand form like @samp{$@@@{listify @var{my-glob}@}}.
+(Conversely, you can explicitly expand a glob as a sublist via
+@samp{$@{listify @var{my-glob}@}}.)
+
+You can further customize the syntax and behavior of globbing in
+Eshell via the Customize group @code{eshell-glob} (@pxref{Easy
+Customization, , , emacs, The GNU Emacs Manual}).
 
 @table @samp
 
@@ -1825,6 +1869,9 @@ garbage output, since the Eshell buffer is not a terminal 
emulator.
 Eshell solves this problem by running such programs in Emacs's
 terminal emulator.
 
+@vindex eshell-visual-commands
+@vindex eshell-visual-subcommands
+@vindex eshell-visual-options
 Programs that need a terminal to display output properly are referred
 to in this manual as ``visual commands'', because they are not simply
 line-oriented.  You must tell Eshell which commands are visual, by
@@ -2042,6 +2089,7 @@ modules.@footnote{ERC provides a similar module facility.}
 @node Optional modules
 @section Optional modules
 
+@vindex eshell-modules-list
 In addition to the various modules enabled by default (documented
 above), Eshell provides several other modules which are @emph{not}
 enabled by default.  If you want to enable these, you can add them to
@@ -2069,6 +2117,7 @@ For example, it binds @kbd{C-u} to kill the current input 
text and
 enabled, it also binds @kbd{C-p} and @kbd{C-n} to move through the
 input history.
 
+@vindex eshell-confine-point-to-input
 If @code{eshell-confine-point-to-input} is non-@code{nil}, this module
 prevents certain commands from causing the point to leave the input
 area, such as @code{backward-word}, @code{previous-line}, etc.
@@ -2386,8 +2435,6 @@ be Eshell's job?
 This would be so that if a Lisp function calls @code{print}, everything
 will happen as it should (albeit slowly).
 
-@item If a globbing pattern returns one match, should it be a list?
-
 @item Make sure syntax table is correct in Eshell mode
 
 So that @kbd{M-@key{DEL}} acts in a predictable manner, etc.
diff --git a/doc/misc/ses.texi b/doc/misc/ses.texi
index 15722056f33..f63bffe2a9f 100644
--- a/doc/misc/ses.texi
+++ b/doc/misc/ses.texi
@@ -1166,7 +1166,7 @@ details-and-summary spreadsheet.
 * Nonrelocatable references::
 * The data area::
 * Buffer-local variables in spreadsheets::
-* Uses of defadvice in @acronym{SES}::
+* Uses of advice-add in @acronym{SES}::
 @end menu
 
 @node Deferred updates
@@ -1308,20 +1308,13 @@ avoid virus warnings, each function used in a formula 
needs
 (put 'your-function-name 'safe-function t)
 @end lisp
 
-@node Uses of defadvice in @acronym{SES}
-@section Uses of defadvice in @acronym{SES}
-@findex defadvice
-@findex undo-more
+@node Uses of advice-add in @acronym{SES}
+@section Uses of advice-add in @acronym{SES}
+@findex advice-add
 @findex copy-region-as-kill
 @findex yank
 
 @table @code
-@item undo-more
-Defines a new undo element format (@var{fun} . @var{args}), which
-means ``undo by applying @var{fun} to @var{args}''.  For spreadsheet
-buffers, it allows undos in the data area even though that's outside
-the narrowing.
-
 @item copy-region-as-kill
 When copying from the print area of a spreadsheet, treat the region as
 a rectangle and attach each cell's formula and printer as 'ses
diff --git a/etc/DEBUG b/etc/DEBUG
index 7c54b488cad..6455152bd50 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -1279,6 +1279,24 @@ code.  To this end, the `--jdb' option will attach the 
Java debugger
 instead of gdbserver.  Lametably, it seems impossible to debug both C
 and Java code in concert.
 
+C code within Emacs rigorously checks for Java exceptions after
+calling any JVM function that may signal an out-of-memory error,
+employing one of the android_exception_check(_N) functions defined
+within android.c for this purpose.  These functions operate presuming
+the preceding Java code does not signal exceptions of its own, and
+report out-of-memory errors upon any type of exception, not just OOM
+errors.
+
+If Emacs protests that it is out of memory, yet you witness a
+substantial amount of free space remaining, search the log buffer for
+a string containing:
+
+  "Possible out of memory error.  The Java exception follows:"
+
+subsequent to which a reproduction of the exception precipitating the
+spurious OOM error should be located.  This exception is invariably
+indicative of a bug within Emacs that should be fixed.
+
 
 This file is part of GNU Emacs.
 
diff --git a/etc/NEWS b/etc/NEWS
index c97df11042d..9d356240f9c 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -312,6 +312,13 @@ of arguments into a command, such as when defining 
aliases.  For more
 information, see the "(eshell) Dollars Expansion" node in the Eshell
 manual.
 
++++
+*** You can now splice Eshell globs in-place into argument lists.
+By setting 'eshell-glob-splice-results' to a non-nil value, Eshell
+will expand glob results in-place as if you had typed each matching
+file name individually.  For more information, see the "(eshell)
+Globbing" node in the Eshell manual.
+
 +++
 *** Eshell now supports negative numbers and ranges for indices.
 Now, you can retrieve the last element of a list with '$my-list[-1]'
@@ -722,6 +729,17 @@ the needs of users with red-green or blue-yellow color 
deficiency.
 The Info manual "(modus-themes) Top" describes the details and
 showcases all their customization options.
 
+** Project
+
+*** New user option 'project-file-history-behavior'.
+Customizing it to 'relativize' makes commands like 'project-find-file'
+and 'project-find-dir' display previous history entries relative to
+the current project.
+
+*** New user option 'project-key-prompt-style'.
+The look of the key prompt in the project switcher has been changed
+slightly.  To get the previous one, set this option to 'brackets'.
+
 
 * Incompatible Lisp Changes in Emacs 30.1
 
@@ -828,9 +846,10 @@ within 'function-key-map' or 'input-decode-map' around 
those calls.
 ** New variables describing the names of built in programs.
 The new variables 'ctags-program-name', 'ebrowse-program-name',
 'etags-program-name', 'hexl-program-name', 'emacsclient-program-name'
-and 'movemail-program-name' should be used instead of "ctags",
-"ebrowse", "etags", "hexl", and "emacsclient", when starting one of
-these built in programs in a subprocess.
+'movemail-program-name', and 'rcs2log-program-name' should be used
+instead of "ctags", "ebrowse", "etags", "hexl", "emacsclient", and
+"rcs2log", when starting one of these built in programs in a
+subprocess.
 
 +++
 ** 'x-popup-menu' now understands touch screen events.
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 265e28e5ddc..c139f25e086 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -1219,8 +1219,8 @@ And restart Emacs.
 This is due to an old bug in the implementation of the X protocol's
 XIM transport: when an input method crashes for some reason, Xlib
 cannot recover.  Emacs cannot do anything about this except wait for
-the I-Bux developers to fix their crashes.  You can work around these
-problems by disabling XIM in your X resources:
+input method developers to fix their crashes.  You can work around
+these problems by disabling XIM in your X resources:
 
   Emacs.useXIM: false
 
@@ -3453,6 +3453,47 @@ Then, reassemble the font from the modified XML:
 which should produce a modified font by the name of
 Anonymous_Pro#1.ttf.
 
+** The "IBM Plex Mono" font displays incorrectly.
+
+This problem is precipitated by an attempt to exploit the undocumented
+feature of the MS font scaler explicated within the previous heading.
+
+Its remedy is also unsurprisingly alike the fix described there: both
+patching the preprogram to reset the point movement vectors and
+replacing the instruction code with code generated by "ttfautohint"
+will adequately resolve the problem.
+
+** Glyphs are missing within the "Arial" font or it does not load.
+
+On account of its origins at Microsoft, instruction code included
+within this font is awash with references to behavior specific to the
+MS scaler.  It is incorrigibly broken, to a degree that even
+"ttfautohint" cannot repair; your only recourse is to select some
+other font.
+
+This issue may extend beyond Arial to encompass a larger selection of
+fonts designed by Microsoft.
+
+** Some TrueType test fonts don't work.
+
+It is unlikely that any of these fonts will really prove useful for
+text editing tasks, since they are designed for the express purpose of
+testing a TrueType font scaler.  The following explanation is present
+only to satisfy a cat-like curiosity.
+
+Most TrueType test fonts "hide" points by moving them to a
+preposterous location outside the confines of the glyph bounding box.
+The Microsoft scaler and FreeType promptly disregard such points.
+
+Nothing in the TrueType specifications implies that points "hidden" in
+this fashion should be afforded any special treatment, and thus Emacs
+eschews doing so.  Consequentially, black streaks are displayed as
+Emacs interpolates glyph edges between points within the glyph and
+points the test font attempts to hide.
+
+Since this behavior does not influence the display of real fonts, no
+action will be taken to address this problem.
+
 ** CJK text does not display in Emacs, but does in other programs.
 
 When inserting CJK text into a buffer or visiting a file containing
diff --git a/java/Makefile.in b/java/Makefile.in
index 804d4669c7a..87683f12544 100644
--- a/java/Makefile.in
+++ b/java/Makefile.in
@@ -227,6 +227,13 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
            cp -f $$file install_temp/lib/$(ANDROID_ABI);       \
          fi                                                    \
        done
+# Next, produce a version of rcs2log befitting Android's naming
+# conventions and shell interpreter location.
+       $(AM_V_at) \
+       sed 's|/bin/sh|/system/bin/sh|'                                 \
+        $(top_srcdir)/lib-src/rcs2log >                                \
+        install_temp/lib/$(ANDROID_ABI)/librcs2log.so
+       $(AM_V_at) chmod +x install_temp/lib/$(ANDROID_ABI)/librcs2log.so
 ifneq ($(NDK_BUILD_SHARED),)
        $(AM_V_SILENT) cp -f $(NDK_BUILD_SHARED) \
          install_temp/lib/$(ANDROID_ABI)
diff --git a/java/README b/java/README
index a6adb805b9e..e518e9fbb2f 100644
--- a/java/README
+++ b/java/README
@@ -1046,4 +1046,3 @@ public class Foo
 {
   Object bar;
 };
-
diff --git a/java/org/gnu/emacs/EmacsDesktopNotification.java 
b/java/org/gnu/emacs/EmacsDesktopNotification.java
index c6ebbc6ae48..121d8f481a2 100644
--- a/java/org/gnu/emacs/EmacsDesktopNotification.java
+++ b/java/org/gnu/emacs/EmacsDesktopNotification.java
@@ -144,7 +144,7 @@ public final class EmacsDesktopNotification
     intent = new Intent (context, EmacsActivity.class);
     intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
 
-    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S)
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
       pending = PendingIntent.getActivity (context, 0, intent,
                                           PendingIntent.FLAG_IMMUTABLE);
     else
diff --git a/java/org/gnu/emacs/EmacsSdk11Clipboard.java 
b/java/org/gnu/emacs/EmacsSdk11Clipboard.java
index 4959ec36eed..b34753922b8 100644
--- a/java/org/gnu/emacs/EmacsSdk11Clipboard.java
+++ b/java/org/gnu/emacs/EmacsSdk11Clipboard.java
@@ -71,10 +71,6 @@ public final class EmacsSdk11Clipboard extends EmacsClipboard
   public synchronized void
   onPrimaryClipChanged ()
   {
-    Log.d (TAG, ("onPrimaryClipChanged: "
-                + monitoredClipboardChangedCount
-                + " " + clipboardChangedCount));
-
     /* Increment monitoredClipboardChangeCount.  If it is now greater
        than clipboardChangedCount, then Emacs no longer owns the
        clipboard.  */
@@ -187,6 +183,10 @@ public final class EmacsSdk11Clipboard extends 
EmacsClipboard
     /* N.B. that Android calls the clipboard the ``primary clip''; it
        is not related to the X primary selection.  */
     clip = manager.getPrimaryClip ();
+
+    if (clip == null)
+      return null;
+
     description = clip.getDescription ();
     i = description.getMimeTypeCount ();
     typeArray = new byte[i][i];
@@ -237,14 +237,12 @@ public final class EmacsSdk11Clipboard extends 
EmacsClipboard
        return null;
       }
 
-    Log.d (TAG, "getClipboardData: "+ mimeType);
-
     /* Now obtain the clipboard data and the data corresponding to
        that MIME type.  */
 
     data = manager.getPrimaryClip ();
 
-    if (data.getItemCount () < 1)
+    if (data == null || data.getItemCount () < 1)
       return null;
 
     try
@@ -254,8 +252,6 @@ public final class EmacsSdk11Clipboard extends 
EmacsClipboard
        if (uri == null)
          return null;
 
-       Log.d (TAG, "getClipboardData: "+ uri);
-
        /* Now open the file descriptor.  */
        assetFd = resolver.openTypedAssetFileDescriptor (uri, mimeType,
                                                         null);
@@ -270,8 +266,6 @@ public final class EmacsSdk11Clipboard extends 
EmacsClipboard
 
        /* Close the original offset.  */
        assetFd.close ();
-
-       Log.d (TAG, "getClipboardData: "+ value);
       }
     catch (FileNotFoundException e)
       {
diff --git a/java/res/drawable/emacs_background.xml 
b/java/res/drawable/emacs_background.xml
index c4562d754d5..c29e0635f7d 100644
--- a/java/res/drawable/emacs_background.xml
+++ b/java/res/drawable/emacs_background.xml
@@ -27,14 +27,14 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>. -->
       android:pathData="M-4.99,-5.79h521.12v526.76h-521.12z"
       android:strokeWidth="10.6667">
     <aapt:attr name="android:fillColor">
-      <gradient 
+      <gradient
           android:startX="0"
           android:startY="0"
           android:endX="512"
           android:endY="512"
           android:type="linear">
         <item android:offset="0" android:color="#FF8381C5"/>
-        <item android:offset="0.34" android:color="#FE806BBC"/>
+        <item android:offset="0.64" android:color="#FE806BBC"/>
         <item android:offset="1" android:color="#FDA52ECB"/>
       </gradient>
     </aapt:attr>
diff --git a/java/res/drawable/emacs_foreground.xml 
b/java/res/drawable/emacs_foreground.xml
index ff9e854d038..68a4631f17b 100644
--- a/java/res/drawable/emacs_foreground.xml
+++ b/java/res/drawable/emacs_foreground.xml
@@ -27,26 +27,12 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>. -->
         android:scaleY="0.6"
         android:translateX="102.4"
         android:translateY="102.4">
-    <path
-        android:pathData="M0,0h512v512h-512z">
-      <aapt:attr name="android:fillColor">
-        <gradient 
-            android:startX="-0"
-            android:startY="256"
-            android:endX="512"
-            android:endY="256"
-            android:type="linear">
-          <item android:offset="1" android:color="#00000000"/>
-          <item android:offset="1" android:color="#FF5B2A85"/>
-        </gradient>
-      </aapt:attr>
-    </path>
     <path
         android:pathData="m174.83,422.11c0,0 19.74,1.4 45.13,-0.84 10.28,-0.91 
49.33,-4.74 78.52,-11.14 0,0 35.59,-7.62 54.63,-14.63 19.92,-7.34 30.76,-13.57 
35.64,-22.4 -0.21,-1.81 1.5,-8.22 -7.68,-12.08 -23.49,-9.85 -50.73,-8.07 
-104.63,-9.21 -59.78,-2.05 -79.66,-12.06 -90.26,-20.12 -10.16,-8.18 
-5.05,-30.79 38.47,-50.71 21.92,-10.61 107.87,-30.19 107.87,-30.19 
-28.95,-14.31 -82.92,-39.46 -94.01,-44.89 -9.73,-4.76 -25.3,-11.94 
-28.68,-20.61 -3.83,-8.33 9.04,-15.51 16.22,-17.56 23.14,-6 [...]
         android:strokeLineJoin="miter"
         android:strokeWidth="0"
         android:fillColor="#ffffff"
-        android:strokeColor="#000000"
+        android:strokeColor="#a0000000"
         android:fillType="evenOdd"
         android:strokeLineCap="butt"/>
   </group>
diff --git a/lisp/arc-mode.el b/lisp/arc-mode.el
index 0a971799746..81d3dfc3432 100644
--- a/lisp/arc-mode.el
+++ b/lisp/arc-mode.el
@@ -2026,6 +2026,7 @@ This doesn't recover lost files, it just undoes changes 
in the buffer itself."
     (setq p (+ p (point-min)))
     (while (string= "PK\001\002" (buffer-substring p (+ p 4)))
       (let* ((creator (get-byte (+ p 5)))
+             (gpflags (archive-l-e (+ p 8) 2))
             ;; (method  (archive-l-e (+ p 10) 2))
              (modtime (archive-l-e (+ p 12) 2))
              (moddate (archive-l-e (+ p 14) 2))
@@ -2037,7 +2038,12 @@ This doesn't recover lost files, it just undoes changes 
in the buffer itself."
              (efnname (let ((str (buffer-substring (+ p 46) (+ p 46 fnlen))))
                        (decode-coding-string
                         str
-                         (or (if (and w32-fname-encoding
+                         ;; Bit 11 of general purpose bit flags (bytes
+                         ;; 8-9) of Central Directory: 1 means UTF-8
+                         ;; encoded file names.
+                         (or (if (/= 0 (logand gpflags #x0800))
+                                 'utf-8-unix)
+                             (if (and w32-fname-encoding
                                       (memq creator
                                             ;; This should be just 10 and
                                             ;; 14, but InfoZip uses 0 and
diff --git a/lisp/completion.el b/lisp/completion.el
index f119fc6028b..eed6e77da4c 100644
--- a/lisp/completion.el
+++ b/lisp/completion.el
@@ -322,9 +322,11 @@ This can be time consuming."
   :type 'boolean)
 
 (defcustom completion-search-distance 15000
-  "How far to search in the buffer when looking for completions.
-In number of characters.  If nil, search the whole buffer."
-  :type 'integer)
+  "How far in the buffer to search when looking for completions.
+Limit is measured in characters.  If nil, search the whole buffer."
+  :type '(choice
+          (const :tag "No limit" nil)
+          (integer :tag "Limit in characters")))
 
 (defcustom completions-merging-modes '(lisp c)
   "List of modes {`c' or `lisp'} for automatic completions merging.
diff --git a/lisp/desktop.el b/lisp/desktop.el
index 59298699914..f096f13ab80 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -455,7 +455,7 @@ If nil, deletes existing frames.
 If `keep', keeps existing frames and does not reuse them."
   :type '(choice (const :tag "Reuse existing frames" t)
                 (const :tag "Delete existing frames" nil)
-                (const :tag "Keep existing frames" :keep))
+                (const :tag "Keep existing frames" keep))
   :group 'desktop
   :version "24.4")
 
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index db8b41aee6a..b8737e5ccd2 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -395,7 +395,8 @@ otherwise it's assumed to be an Info file."
       (with-temp-buffer
         (insert-file-contents file)
         (setq file (make-temp-file "ox-texinfo-"))
-        (org-export-to-file 'texinfo file)
+        (let ((default-directory docs-directory))
+          (org-export-to-file 'texinfo file))
         (setq clean-up t)))
     (with-current-buffer (get-buffer-create " *package-vc doc*")
       (erase-buffer)
@@ -451,13 +452,11 @@ version of that package."
                              (desc (cadr (assoc package pac))))
                         (and desc (seq-some
                                    (apply-partially #'depends-on-p target)
-                                   (package-desc-reqs desc))))))
+                                   (mapcar #'car (package-desc-reqs desc)))))))
                 (dependent-order (a b)
                   (let ((desc-a (package-desc-name a))
                         (desc-b (package-desc-name b)))
-                    (or (not desc-a) (not desc-b)
-                        (not (depends-on-p desc-b desc-a))
-                        (depends-on-p desc-a desc-b)))))
+                    (depends-on-p desc-a desc-b))))
       (mapc #'search requirements)
       (cl-callf sort to-install #'version-order)
       (cl-callf seq-uniq to-install #'duplicate-p)
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 78dc58e0bcd..572822351b1 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -312,9 +312,13 @@ it makes no sense to convert it to a string using
 Like `let', bind variables in BINDINGS and then evaluate BODY,
 but with the twist that BODY can evaluate itself recursively by
 calling NAME, where the arguments passed to NAME are used
-as the new values of the bound variables in the recursive invocation."
+as the new values of the bound variables in the recursive invocation.
+
+This construct can only be used with lexical binding."
   (declare (indent 2) (debug (symbolp (&rest (symbolp form)) body)))
   (require 'cl-lib)
+  (unless lexical-binding
+    (error "`named-let' requires lexical binding"))
   (let ((fargs (mapcar (lambda (b) (if (consp b) (car b) b)) bindings))
         (aargs (mapcar (lambda (b) (if (consp b) (cadr b))) bindings)))
     ;; According to the Scheme semantics of named let, `name' is not in scope
diff --git a/lisp/epa-file.el b/lisp/epa-file.el
index 4d8ca11e809..a27f241c0c3 100644
--- a/lisp/epa-file.el
+++ b/lisp/epa-file.el
@@ -123,9 +123,16 @@ encryption is used."
              (cons "Opening input file" (cdr error))))))
 
 (defun epa--wrong-password-p (context)
+  "Return whether a wrong password caused the error in CONTEXT."
   (let ((error-string (epg-context-error-output context)))
+    ;; Use a strict regexp here that really only matches "wrong
+    ;; passphrase" errors to avoid hiding diagnostic information
+    ;; (bug#65316).  Below regexp also can fail to match non-English
+    ;; messages, since at least the "decryption failed" part of it
+    ;; seems to be localized.  But since this means false negatives
+    ;; this is probably OK.
     (and (string-match
-          "decryption failed: \\(Bad session key\\|No secret key\\)"
+          "decryption failed: \\(Bad session key\\|Bad passphrase\\)"
           error-string)
          (match-string 1 error-string))))
 
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index 732bbb3f1fa..25dccbd695c 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -148,6 +148,10 @@ to writing a completion function."
   (eshell-cmpl--custom-variable-docstring 'pcomplete-dir-ignore)
   :type (get 'pcomplete-dir-ignore 'custom-type))
 
+(defcustom eshell-cmpl-remote-file-ignore nil
+  (eshell-cmpl--custom-variable-docstring 'pcomplete-remote-file-ignore)
+  :type (get 'pcomplete-remote-file-ignore 'custom-type))
+
 (defcustom eshell-cmpl-ignore-case (eshell-under-windows-p)
   (eshell-cmpl--custom-variable-docstring 'completion-ignore-case)
   :type (get 'completion-ignore-case 'custom-type))
@@ -248,6 +252,8 @@ to writing a completion function."
               eshell-cmpl-file-ignore)
   (setq-local pcomplete-dir-ignore
               eshell-cmpl-dir-ignore)
+  (setq-local pcomplete-remote-file-ignore
+              eshell-cmpl-remote-file-ignore)
   (setq-local completion-ignore-case
               eshell-cmpl-ignore-case)
   (setq-local pcomplete-autolist
@@ -325,6 +331,15 @@ to writing a completion function."
             "Failed to evaluate argument form during completion: %S" arg)
      (propertize "\0" 'eshell-argument-stub 'error))))
 
+;; Code stolen from `eshell-plain-command'.
+(defun eshell-external-command-p (command)
+  "Whether an external command shall be called."
+  (let* ((esym (eshell-find-alias-function command))
+        (sym (or esym (intern-soft command))))
+    (not (and sym (fboundp sym)
+             (or esym eshell-prefer-lisp-functions
+                 (not (eshell-search-path command)))))))
+
 (defun eshell-complete-parse-arguments ()
   "Parse the command line arguments for `pcomplete-argument'."
   (when (and eshell-no-completion-during-jobs
@@ -406,6 +421,14 @@ to writing a completion function."
        args posns)
       (setq args (nreverse evaled-args)
             posns (nreverse evaled-posns)))
+    ;; Determine, whether remote file names shall be completed.  They
+    ;; shouldn't for external commands, or when in a pipe.  Respect
+    ;; also `eshell-cmpl-remote-file-ignore', which could be set by
+    ;; the user.
+    (setq-local pcomplete-remote-file-ignore
+                (or eshell-cmpl-remote-file-ignore
+                    eshell-in-pipeline-p ; does not work
+                    (eshell-external-command-p (car args))))
     ;; Convert arguments to forms that Pcomplete can understand.
     (cons (mapcar
            (lambda (arg)
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index d00f8c93cd1..1141b673e97 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -69,6 +69,15 @@ by zsh for filename generation."
   :type 'hook
   :group 'eshell-glob)
 
+(defcustom eshell-glob-splice-results nil
+  "If non-nil, the results of glob patterns will be spliced in-place.
+When splicing, the resulting command is as though the user typed
+each result individually.  Otherwise, the glob results a single
+argument as a list."
+  :version "30.1"
+  :type 'boolean
+  :group 'eshell-glob)
+
 (defcustom eshell-glob-include-dot-files nil
   "If non-nil, glob patterns will match files beginning with a dot."
   :type 'boolean
@@ -139,12 +148,15 @@ This mimics the behavior of zsh if non-nil, but bash if 
nil."
 (defun eshell-no-command-globbing (terms)
   "Don't glob the command argument.  Reflect this by modifying TERMS."
   (ignore
-   (when (and (listp (car terms))
-             (eq (caar terms) 'eshell-extended-glob))
-     (setcar terms (cadr (car terms))))))
+   (pcase (car terms)
+     ((or `(eshell-extended-glob ,term)
+          `(eshell-splice-args (eshell-extended-glob ,term)))
+      (setcar terms term)))))
 
 (defun eshell-add-glob-modifier ()
   "Add `eshell-extended-glob' to the argument modifier list."
+  (when eshell-glob-splice-results
+    (add-to-list 'eshell-current-modifiers 'eshell-splice-args t))
   (add-to-list 'eshell-current-modifiers 'eshell-extended-glob))
 
 (defun eshell-parse-glob-chars ()
@@ -326,7 +338,9 @@ regular expressions, and these cannot support the above 
constructs."
     (or (and eshell-glob-matches (sort eshell-glob-matches #'string<))
        (if eshell-error-if-no-glob
            (error "No matches found: %s" glob)
-         glob))))
+          (if eshell-glob-splice-results
+              (list glob)
+            glob)))))
 
 ;; FIXME does this really need to abuse eshell-glob-matches, message-shown?
 (defun eshell-glob-entries (path globs only-dirs)
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el
index 79232d8e9b5..9d4b72b01df 100644
--- a/lisp/eshell/em-hist.el
+++ b/lisp/eshell/em-hist.el
@@ -381,20 +381,19 @@ Input is entered into the input history ring, if the 
value of
 variable `eshell-input-filter' returns non-nil when called on the
 input."
   (when (and (funcall eshell-input-filter input)
-             (if (eq eshell-hist-ignoredups 'erase)
-                 ;; Remove any old occurrences of the input, and put
-                 ;; the new one at the end.
-                 (unless (ring-empty-p eshell-history-ring)
-                   (ring-remove eshell-history-ring
-                               (ring-member eshell-history-ring input))
-                   t)
-               ;; Always add...
-               (or (null eshell-hist-ignoredups)
-                   ;; ... or add if it's not already present at the
-                   ;; end.
-                  (not (ring-p eshell-history-ring))
-                  (ring-empty-p eshell-history-ring)
-                  (not (string-equal (eshell-get-history 0) input)))))
+             (pcase eshell-hist-ignoredups
+               ('nil t)                 ; Always add to history
+               ('erase                  ; Add, removing any old occurrences
+                (when-let ((old-index (ring-member eshell-history-ring input)))
+                  ;; Remove the old occurence of this input so we can
+                  ;; add it to the end.  FIXME: Should we try to
+                  ;; remove multiple old occurrences, e.g. if the user
+                  ;; recently changed to using `erase'?
+                  (ring-remove eshell-history-ring old-index))
+                t)
+               (_                       ; Add if not already the latest entry
+                (or (ring-empty-p eshell-history-ring)
+                    (not (string-equal (eshell-get-history 0) input))))))
     (eshell-put-history input))
   (setq eshell-save-history-index eshell-history-index)
   (setq eshell-history-index nil))
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el
index bfb0dad60ef..1d67f1af990 100644
--- a/lisp/eshell/em-pred.el
+++ b/lisp/eshell/em-pred.el
@@ -301,16 +301,25 @@ This function is specially for adding onto 
`eshell-parse-argument-hook'."
                    (modifiers (eshell-parse-modifiers))
                   (preds (car modifiers))
                   (mods (cdr modifiers)))
-             (if (or preds mods)
-                 ;; has to go at the end, which is only natural since
-                 ;; syntactically it can only occur at the end
-                 (setq eshell-current-modifiers
-                       (append
-                        eshell-current-modifiers
-                        (list
-                         (lambda (lst)
-                           (eshell-apply-modifiers
-                            lst preds mods modifier-string))))))))
+              (when (or preds mods)
+                ;; Has to go at the end, which is only natural since
+                ;; syntactically it can only occur at the end.
+                (setq eshell-current-modifiers
+                      (append
+                       eshell-current-modifiers
+                       (list
+                        (lambda (lst)
+                          (eshell-apply-modifiers
+                           lst preds mods modifier-string)))))
+                (when (memq 'eshell-splice-args eshell-current-modifiers)
+                  ;; If splicing results, ensure that
+                  ;; `eshell-splice-args' is the last modifier.
+                  ;; Eshell's command parsing can't handle it anywhere
+                  ;; else.
+                  (setq eshell-current-modifiers
+                        (append (delq 'eshell-splice-args
+                                      eshell-current-modifiers)
+                                (list 'eshell-splice-args)))))))
          (goto-char (1+ end))
          (eshell-finish-arg))))))
 
diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index cccdb49ce2a..c07f871dd37 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -423,57 +423,6 @@ If HANDLES is nil, use `eshell-current-handles'."
   (eshell-set-output-handle eshell-output-handle mode target handles)
   (eshell-copy-output-handle eshell-error-handle eshell-output-handle handles))
 
-(defun eshell-close-target (target status)
-  "Close an output TARGET, passing STATUS as the result.
-STATUS should be non-nil on successful termination of the output."
-  (cond
-   ((symbolp target) nil)
-
-   ;; If we were redirecting to a file, save the file and close the
-   ;; buffer.
-   ((markerp target)
-    (let ((buf (marker-buffer target)))
-      (when buf                         ; somebody's already killed it!
-       (save-current-buffer
-         (set-buffer buf)
-         (when eshell-output-file-buffer
-           (save-buffer)
-           (when (eq eshell-output-file-buffer t)
-             (or status (set-buffer-modified-p nil))
-             (kill-buffer buf)))))))
-
-   ;; If we're redirecting to a process (via a pipe, or process
-   ;; redirection), send it EOF so that it knows we're finished.
-   ((eshell-processp target)
-    ;; According to POSIX.1-2017, section 11.1.9, when communicating
-    ;; via terminal, sending EOF causes all bytes waiting to be read
-    ;; to be sent to the process immediately.  Thus, if there are any
-    ;; bytes waiting, we need to send EOF twice: once to flush the
-    ;; buffer, and a second time to cause the next read() to return a
-    ;; size of 0, indicating end-of-file to the reading process.
-    ;; However, some platforms (e.g. Solaris) actually require sending
-    ;; a *third* EOF.  Since sending extra EOFs while the process is
-    ;; running are a no-op, we'll just send the maximum we'd ever
-    ;; need.  See bug#56025 for further details.
-    (let ((i 0)
-          ;; Only call `process-send-eof' once if communicating via a
-          ;; pipe (in truth, this just closes the pipe).
-          (max-attempts (if (process-tty-name target 'stdin) 3 1)))
-      (while (and (<= (cl-incf i) max-attempts)
-                  (eq (process-status target) 'run))
-        (process-send-eof target))))
-
-   ;; A plain function redirection needs no additional arguments
-   ;; passed.
-   ((functionp target)
-    (funcall target status))
-
-   ;; But a more complicated function redirection (which can only
-   ;; happen with aliases at the moment) has arguments that need to be
-   ;; passed along with it.
-   ((consp target)
-    (apply (car target) status (cdr target)))))
-
 (defun eshell-kill-append (string)
   "Call `kill-append' with STRING, if it is indeed a string."
   (if (stringp string)
@@ -485,56 +434,6 @@ STATUS should be non-nil on successful termination of the 
output."
       (let ((select-enable-clipboard t))
        (kill-append string nil))))
 
-(defun eshell-get-target (target &optional mode)
-  "Convert TARGET, which is a raw argument, into a valid output target.
-MODE is either `overwrite', `append' or `insert'; if it is omitted or nil,
-it defaults to `insert'."
-  (setq mode (or mode 'insert))
-  (cond
-   ((stringp target)
-    (let ((redir (assoc target eshell-virtual-targets)))
-      (if redir
-         (if (nth 2 redir)
-             (funcall (nth 1 redir) mode)
-           (nth 1 redir))
-       (let* ((exists (get-file-buffer target))
-              (buf (find-file-noselect target t)))
-         (with-current-buffer buf
-           (if buffer-file-read-only
-               (error "Cannot write to read-only file `%s'" target))
-           (setq buffer-read-only nil)
-            (setq-local eshell-output-file-buffer
-                        (if (eq exists buf) 0 t))
-           (cond ((eq mode 'overwrite)
-                  (erase-buffer))
-                 ((eq mode 'append)
-                  (goto-char (point-max))))
-           (point-marker))))))
-
-
-   ((bufferp target)
-    (with-current-buffer target
-      (cond ((eq mode 'overwrite)
-             (erase-buffer))
-            ((eq mode 'append)
-             (goto-char (point-max))))
-      (point-marker)))
-
-   ((functionp target) nil)
-
-   ((symbolp target)
-    (if (eq mode 'overwrite)
-       (set target nil))
-    target)
-
-   ((or (eshell-processp target)
-       (markerp target))
-    target)
-
-   (t
-    (error "Invalid redirection target: %s"
-          (eshell-stringify target)))))
-
 (defun eshell-interactive-output-p (&optional index handles)
   "Return non-nil if the specified handle is bound for interactive display.
 HANDLES is the set of handles to check; if nil, use
@@ -599,55 +498,168 @@ after all printing is over with no argument."
   (eshell-print object)
   (eshell-print "\n"))
 
-(defun eshell-output-object-to-target (object target)
-  "Insert OBJECT into TARGET.
-Returns what was actually sent, or nil if nothing was sent."
-  (cond
-   ((functionp target)
-    (funcall target object))
-
-   ((symbolp target)
-    (if (eq target t)                   ; means "print to display"
-       (eshell-interactive-print (eshell-stringify object))
-      (if (not (symbol-value target))
-         (set target object)
-       (setq object (eshell-stringify object))
-       (if (not (stringp (symbol-value target)))
-           (set target (eshell-stringify
-                        (symbol-value target))))
-       (set target (concat (symbol-value target) object)))))
-
-   ((markerp target)
-    (if (buffer-live-p (marker-buffer target))
-       (with-current-buffer (marker-buffer target)
-         (let ((moving (= (point) target)))
-           (save-excursion
-             (goto-char target)
-             (unless (stringp object)
-               (setq object (eshell-stringify object)))
-             (insert-and-inherit object)
-             (set-marker target (point-marker)))
-           (if moving
-               (goto-char target))))))
-
-   ((eshell-processp target)
-    (unless (stringp object)
-      (setq object (eshell-stringify object)))
-    (condition-case err
-        (process-send-string target object)
-      (error
-       ;; If `process-send-string' raises an error and the process has
-       ;; finished, treat it as a broken pipe.  Otherwise, just
-       ;; re-throw the signal.
-       (if (memq (process-status target)
-                '(run stop open closed))
-           (signal (car err) (cdr err))
-         (signal 'eshell-pipe-broken (list target))))))
-
-   ((consp target)
-    (apply (car target) object (cdr target))))
+(cl-defstruct (eshell-virtual-target
+               (:constructor nil)
+               (:constructor eshell-virtual-target-create (output-function)))
+  "A virtual target (see `eshell-virtual-targets')."
+  output-function)
+
+(cl-defgeneric eshell-get-target (raw-target &optional _mode)
+  "Convert RAW-TARGET, which is a raw argument, into a valid output target.
+MODE is either `overwrite', `append' or `insert'; if it is omitted or nil,
+it defaults to `insert'."
+  (error "Invalid redirection target: %s" (eshell-stringify raw-target)))
+
+(cl-defmethod eshell-get-target ((raw-target string) &optional mode)
+  "Convert a string RAW-TARGET into a valid output target using MODE.
+If TARGET is a virtual target (see `eshell-virtual-targets'),
+return an `eshell-virtual-target' instance; otherwise, return a
+marker for a file named TARGET."
+  (setq mode (or mode 'insert))
+  (if-let ((redir (assoc raw-target eshell-virtual-targets)))
+      (eshell-virtual-target-create
+       (if (nth 2 redir)
+           (funcall (nth 1 redir) mode)
+         (nth 1 redir)))
+    (let ((exists (get-file-buffer raw-target))
+          (buf (find-file-noselect raw-target t)))
+      (with-current-buffer buf
+        (when buffer-file-read-only
+          (error "Cannot write to read-only file `%s'" raw-target))
+          (setq buffer-read-only nil)
+          (setq-local eshell-output-file-buffer
+                      (if (eq exists buf) 0 t))
+          (cond ((eq mode 'overwrite)
+                 (erase-buffer))
+                ((eq mode 'append)
+                 (goto-char (point-max))))
+          (point-marker)))))
+
+(cl-defmethod eshell-get-target ((raw-target buffer) &optional mode)
+  "Convert a buffer RAW-TARGET into a valid output target using MODE.
+This returns a marker for that buffer."
+  (with-current-buffer raw-target
+    (cond ((eq mode 'overwrite)
+           (erase-buffer))
+          ((eq mode 'append)
+           (goto-char (point-max))))
+    (point-marker)))
+
+(cl-defmethod eshell-get-target ((raw-target symbol) &optional mode)
+  "Convert a symbol RAW-TARGET into a valid output target using MODE.
+This returns RAW-TARGET, with its value initialized to nil if MODE is
+`overwrite'."
+  (when (eq mode 'overwrite)
+    (set raw-target nil))
+  raw-target)
+
+(cl-defmethod eshell-get-target ((raw-target process) &optional _mode)
+  "Convert a process RAW-TARGET into a valid output target.
+This just returns RAW-TARGET."
+  raw-target)
+
+(cl-defmethod eshell-get-target ((raw-target marker) &optional _mode)
+  "Convert a marker RAW-TARGET into a valid output target.
+This just returns RAW-TARGET."
+  raw-target)
+
+(cl-defgeneric eshell-close-target (target status)
+  "Close an output TARGET, passing STATUS as the result.
+STATUS should be non-nil on successful termination of the output.")
+
+(cl-defmethod eshell-close-target ((_target symbol) _status)
+  "Close a symbol TARGET."
+  nil)
+
+(cl-defmethod eshell-close-target ((target marker) status)
+  "Close a marker TARGET.
+If TARGET was created from a file name, save and kill the buffer.
+If status is nil, prompt before killing."
+  (when (buffer-live-p (marker-buffer target))
+    (with-current-buffer (marker-buffer target)
+      (when eshell-output-file-buffer
+        (save-buffer)
+        (when (eq eshell-output-file-buffer t)
+          (or status (set-buffer-modified-p nil))
+          (kill-buffer))))))
+
+(cl-defmethod eshell-close-target ((target process) _status)
+  "Close a process TARGET."
+  ;; According to POSIX.1-2017, section 11.1.9, when communicating via
+  ;; terminal, sending EOF causes all bytes waiting to be read to be
+  ;; sent to the process immediately.  Thus, if there are any bytes
+  ;; waiting, we need to send EOF twice: once to flush the buffer, and
+  ;; a second time to cause the next read() to return a size of 0,
+  ;; indicating end-of-file to the reading process.  However, some
+  ;; platforms (e.g. Solaris) actually require sending a *third* EOF.
+  ;; Since sending extra EOFs to a running process is a no-op, we'll
+  ;; just send the maximum we'd ever need.  See bug#56025 for further
+  ;; details.
+  (catch 'done
+    (dotimes (_ (if (process-tty-name target 'stdin) 3 1))
+      (unless (process-live-p target)
+        (throw 'done nil))
+      (process-send-eof target))))
+
+(cl-defmethod eshell-close-target ((_target eshell-virtual-target) _status)
+  "Close a virtual TARGET."
+  nil)
+
+(cl-defgeneric eshell-output-object-to-target (object target)
+  "Output OBJECT to TARGET.
+Returns what was actually sent, or nil if nothing was sent.")
+
+(cl-defmethod eshell-output-object-to-target (object (_target (eql t)))
+  "Output OBJECT to the display."
+  (setq object (eshell-stringify object))
+  (eshell-interactive-print object))
+
+(cl-defmethod eshell-output-object-to-target (object (target symbol))
+  "Output OBJECT to the value of the symbol TARGET."
+  (if (not (symbol-value target))
+      (set target object)
+    (setq object (eshell-stringify object))
+    (if (not (stringp (symbol-value target)))
+        (set target (eshell-stringify
+                     (symbol-value target))))
+    (set target (concat (symbol-value target) object)))
+  object)
+
+(cl-defmethod eshell-output-object-to-target (object (target marker))
+  "Output OBJECT to the marker TARGET."
+  (when (buffer-live-p (marker-buffer target))
+    (with-current-buffer (marker-buffer target)
+      (let ((moving (= (point) target)))
+        (save-excursion
+          (goto-char target)
+          (unless (stringp object)
+            (setq object (eshell-stringify object)))
+          (insert-and-inherit object)
+          (set-marker target (point-marker)))
+        (when moving
+          (goto-char target)))))
+  object)
+
+(cl-defmethod eshell-output-object-to-target (object (target process))
+  "Output OBJECT to the process TARGET."
+  (unless (stringp object)
+    (setq object (eshell-stringify object)))
+  (condition-case err
+      (process-send-string target object)
+    (error
+     ;; If `process-send-string' raises an error and the process has
+     ;; finished, treat it as a broken pipe.  Otherwise, just
+     ;; re-throw the signal.
+     (if (process-live-p target)
+         (signal (car err) (cdr err))
+       (signal 'eshell-pipe-broken (list target)))))
   object)
 
+(cl-defmethod eshell-output-object-to-target (object
+                                              (target eshell-virtual-target))
+  "Output OBJECT to the virtual TARGET."
+  (funcall (eshell-virtual-target-output-function target) object))
+
 (defun eshell-output-object (object &optional handle-index handles)
   "Insert OBJECT, using HANDLE-INDEX specifically.
 If HANDLE-INDEX is nil, output to `eshell-output-handle'.
diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el
index 00e0c8014e1..f2d20b4cded 100644
--- a/lisp/eshell/esh-proc.el
+++ b/lisp/eshell/esh-proc.el
@@ -157,17 +157,14 @@ The signals which will cause this to happen are matched by
     (eshell-reset)))
 
 (defun eshell-wait-for-process (&rest procs)
-  "Wait until PROC has successfully completed."
-  (while procs
-    (let ((proc (car procs)))
-      (when (eshell-processp proc)
-       ;; NYI: If the process gets stopped here, that's bad.
-       (while (assq proc eshell-process-list)
-         (if (input-pending-p)
-             (discard-input))
-         (sit-for eshell-process-wait-seconds
-                  eshell-process-wait-milliseconds))))
-    (setq procs (cdr procs))))
+  "Wait until PROCS have successfully completed."
+  (dolist (proc procs)
+    (when (eshell-processp proc)
+      (while (process-live-p proc)
+        (when (input-pending-p)
+          (discard-input))
+        (sit-for eshell-process-wait-seconds
+                 eshell-process-wait-milliseconds)))))
 
 (defalias 'eshell/wait #'eshell-wait-for-process)
 
@@ -506,16 +503,14 @@ If ALL is non-nil, background processes will be 
interacted with as well.
 If QUERY is non-nil, query the user with QUERY before calling FUNC."
   (let (defunct result)
     (dolist (entry eshell-process-list)
-      (if (and (memq (process-status (car entry))
-                   '(run stop open closed))
+      (if (and (process-live-p (car entry))
               (or all
                   (not (cdr entry)))
               (or (not query)
                   (y-or-n-p (format-message query
                                             (process-name (car entry))))))
          (setq result (funcall func (car entry))))
-      (unless (memq (process-status (car entry))
-                   '(run stop open closed))
+      (unless (process-live-p (car entry))
        (setq defunct (cons entry defunct))))
     ;; clean up the process list; this can get dirty if an error
     ;; occurred that brought the user into the debugger, and then they
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index c7c0a21d2a9..711c35f8527 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -162,6 +162,13 @@ if they are quoted with a backslash."
     ("COLUMNS" ,(lambda () (window-body-width nil 'remap)) t t)
     ("LINES" ,(lambda () (window-body-height nil 'remap)) t t)
     ("INSIDE_EMACS" eshell-inside-emacs t)
+    ("PAGER" (,(lambda () (or comint-pager (getenv "PAGER")))
+              . ,(lambda (_ value)
+                   ;; When unsetting PAGER, be sure to clear its value
+                   ;; from `process-environment' too.
+                   (unless value (setenv "PAGER"))
+                   (setq comint-pager value)))
+     t t)
     ("UID" ,(lambda () (file-user-uid)) nil t)
     ("GID" ,(lambda () (file-group-gid)) nil t)
 
@@ -262,11 +269,13 @@ copied (a.k.a. \"exported\") to the environment of 
created subprocesses."
   ;; changing a variable will affect all of Emacs.
   (unless eshell-modify-global-environment
     (setq-local process-environment (eshell-copy-environment)))
+  (make-local-variable 'comint-pager)
   (setq-local eshell-subcommand-bindings
               (append
                '((process-environment (eshell-copy-environment))
                  (eshell-variable-aliases-list eshell-variable-aliases-list)
-                 (eshell-path-env-list eshell-path-env-list))
+                 (eshell-path-env-list eshell-path-env-list)
+                 (comint-pager comint-pager))
                eshell-subcommand-bindings))
 
   (setq-local eshell-special-chars-inside-quoting
diff --git a/lisp/face-remap.el b/lisp/face-remap.el
index 3ec271b67a4..c5f7af37406 100644
--- a/lisp/face-remap.el
+++ b/lisp/face-remap.el
@@ -70,21 +70,10 @@
    :foreground :background :stipple :overline :strike-through :box
    :font :inherit :fontset :distant-foreground :extend :vector])
 
-(defun face-remap--copy-face (val)
-  "Return a copy of the `face' property value VAL."
-  ;; A `face' property can be either a face name (a symbol), or a face
-  ;; property list like (:foreground "red" :inherit default),
-  ;; or a list of such things.
-  ;; FIXME: This should probably be shared to some extent with
-  ;; `add-face-text-property'.
-  (if (or (not (listp val)) (keywordp (car val)))
-      val
-    (copy-sequence val)))
-
 (defun face-attrs--make-indirect-safe ()
   "Deep-copy the buffer's `face-remapping-alist' upon cloning the buffer."
   (setq-local face-remapping-alist
-              (mapcar #'face-remap--copy-face face-remapping-alist)))
+              (mapcar #'copy-tree face-remapping-alist)))
 
 (add-hook 'clone-indirect-buffer-hook #'face-attrs--make-indirect-safe)
 
diff --git a/lisp/files.el b/lisp/files.el
index 26fd1eee5d7..8f25e8562e0 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -1283,10 +1283,8 @@ Tip: You can use this expansion of remote identifier 
components
      returns a remote file name for file \"/bin/sh\" that has the
      same remote identifier as FILE but expanded; a name such as
      \"/sudo:root@myhost:/bin/sh\"."
-  (let ((handler (find-file-name-handler file 'file-remote-p)))
-    (if handler
-       (funcall handler 'file-remote-p file identification connected)
-      nil)))
+  (when-let ((handler (find-file-name-handler file 'file-remote-p)))
+    (funcall handler 'file-remote-p file identification connected)))
 
 ;; Probably this entire variable should be obsolete now, in favor of
 ;; something Tramp-related (?).  It is not used in many places.
diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el
index 98a7e23428b..839e5d203ff 100644
--- a/lisp/gnus/gnus-search.el
+++ b/lisp/gnus/gnus-search.el
@@ -1434,6 +1434,9 @@ Returns a list of [group article score] vectors."
                     ""))
         (groups (mapcar #'gnus-group-short-name groups))
        artlist article group)
+    (when (>= gnus-verbose 7)
+      (gnus-message 7 "Search engine returned %d results"
+                    (car (buffer-line-statistics))))
     (goto-char (point-min))
     ;; Prep prefix, we want to at least be removing the root
     ;; filesystem separator.
@@ -1485,6 +1488,10 @@ Returns a list of [group article score] vectors."
     ;; Are we running an additional grep query?
     (when-let ((grep-reg (alist-get 'grep query)))
       (setq artlist (gnus-search-grep-search engine artlist grep-reg)))
+
+    (when (>= gnus-verbose 7)
+      (gnus-message 7 "Gnus search returning %d results"
+                    (length artlist)))
     ;; Munge into the list of vectors expected by nnselect.
     (mapcar (pcase-lambda (`(,_ ,article ,group ,score))
               (vector
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 11854680dc2..22cfbbc39cd 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -153,7 +153,12 @@ edited even if this option is enabled."
   :version "28.1")
 
 (defcustom help-display-function-type t
-  "If non-nil, display the type of a function when available."
+  "Whether to display type specifiers of functions in \"*Help*\" buffers.
+
+The type specifier of a function is returned by `comp-function-type-spec',
+which see.  When this variable is non-nil, \\[describe-function] will \
+display the function's
+type specifier when available."
   :type 'boolean
   :group 'help
   :version "30.1")
@@ -1079,10 +1084,8 @@ Returns a list of the form (REAL-FUNCTION DEF ALIASED 
REAL-DEF)."
                  (concat beg "byte-compiled Lisp function"))
                  ((module-function-p def)
                   (concat beg "module function"))
-                ((eq (car-safe def) 'lambda)
+                ((memq (car-safe def) '(lambda closure))
                  (concat beg "Lisp function"))
-                ((eq (car-safe def) 'closure)
-                 (concat beg "Lisp closure"))
                 ((keymapp def)
                  (let ((is-full nil)
                        (elts (cdr-safe def)))
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index fa28c1bf7a5..713125d4e58 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -248,8 +248,9 @@ Stop if the right edge of the image is reached."
         (image-set-window-hscroll (max 0 (+ (window-hscroll) n))))
        (t
         (let* ((image (image-get-display-property))
-               (edges (window-inside-edges))
-               (win-width (- (nth 2 edges) (nth 0 edges)))
+               (edges (window-edges nil t nil t))
+               (win-width (- (/ (nth 2 edges) (frame-char-width))
+                              (/ (nth 0 edges) (frame-char-width))))
                (img-width (ceiling (car (image-display-size image)))))
           (image-set-window-hscroll (min (max 0 (- img-width win-width))
                                          (+ n (window-hscroll))))))))
diff --git a/lisp/image/image-dired.el b/lisp/image/image-dired.el
index 8e2e4c6f644..83f228b2d59 100644
--- a/lisp/image/image-dired.el
+++ b/lisp/image/image-dired.el
@@ -724,21 +724,22 @@ On reaching end or beginning of buffer, stop and show a 
message."
               (not (if reverse (bobp) (eobp))))
     (forward-char (if reverse -1 1))))
 
-(defmacro image-dired--movement-command (to &optional reverse)
-  `(progn
-     (goto-char ,to)
-     (image-dired--movement-ensure-point-pos ,reverse)
-     (when image-dired-track-movement
-       (image-dired-track-original-file))
-     (image-dired--update-header-line)))
-
-(defmacro image-dired--movement-command-line (&optional reverse)
-  `(image-dired--movement-command
-     (let ((goal-column (current-column)))
-       (forward-line ,(if reverse -1 1))
-       (move-to-column goal-column)
-       (point))
-     ,reverse))
+(defun image-dired--update-after-move (reverse)
+  "Book-keeping after move."
+  (image-dired--movement-ensure-point-pos reverse)
+  (when image-dired-track-movement
+    (image-dired-track-original-file))
+  (image-dired--update-header-line))
+
+(defun image-dired--movement-command (to &optional reverse)
+  (goto-char to)
+  (image-dired--update-after-move reverse))
+
+(defun image-dired--movement-command-line (&optional reverse)
+  (let ((goal-column (current-column)))
+    (forward-line (if reverse -1 1))
+    (move-to-column goal-column)
+    (image-dired--update-after-move reverse)))
 
 (defun image-dired-next-line ()
   "Move to next line in the thumbnail buffer."
@@ -775,10 +776,7 @@ On reaching end or beginning of buffer, stop and show a 
message."
   (let ((goal-column (current-column)))
     (if down (scroll-down) (scroll-up))
     (move-to-column goal-column)
-    (image-dired--movement-ensure-point-pos down)
-    (when image-dired-track-movement
-      (image-dired-track-original-file))
-    (image-dired--update-header-line)))
+    (image-dired--update-after-move down)))
 
 (defun image-dired-scroll-up ()
   (interactive nil image-dired-thumbnail-mode)
diff --git a/lisp/keymap.el b/lisp/keymap.el
index cd06b830e0a..017b2d6ead0 100644
--- a/lisp/keymap.el
+++ b/lisp/keymap.el
@@ -78,7 +78,7 @@ called from Lisp, COMMAND can be anything that `keymap-set' 
accepts
 as its DEFINITION argument.
 
 If COMMAND is a string (which can only happen when this function is
-callled from Lisp), it must satisfy `key-valid-p'.
+called from Lisp), it must satisfy `key-valid-p'.
 
 Note that if KEY has a local binding in the current buffer,
 that local binding will continue to shadow any global binding
@@ -102,7 +102,7 @@ called from Lisp, COMMAND can be anything that `keymap-set' 
accepts
 as its DEFINITION argument.
 
 If COMMAND is a string (which can only happen when this function is
-callled from Lisp), it must satisfy `key-valid-p'.
+called from Lisp), it must satisfy `key-valid-p'.
 
 The binding goes in the current buffer's local keymap, which in most
 cases is shared with all other buffers in the same major mode."
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index 16ec33f92dc..3d64b7976b3 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -4233,7 +4233,7 @@ directory, so that Emacs will know its current contents."
         (host (nth 0 parsed))
         (user (nth 1 parsed))
         (localname (nth 2 parsed)))
-    (and (or (not connected)
+    (and (or (memq connected '(nil never))
             (let ((proc (get-process (ange-ftp-ftp-process-buffer host user))))
               (and proc (processp proc)
                    (memq (process-status proc) '(run open)))))
diff --git a/lisp/net/tramp-cmds.el b/lisp/net/tramp-cmds.el
index 87651d60328..8d95adb597c 100644
--- a/lisp/net/tramp-cmds.el
+++ b/lisp/net/tramp-cmds.el
@@ -52,6 +52,7 @@ SYNTAX can be one of the symbols `default' (default),
   (when syntax
     (customize-set-variable 'tramp-syntax syntax)))
 
+;; Use `match-buffers' starting with Emacs 29.1.
 ;;;###tramp-autoload
 (defun tramp-list-tramp-buffers ()
   "Return a list of all Tramp connection buffers."
@@ -63,6 +64,7 @@ SYNTAX can be one of the symbols `default' (default),
    (all-completions
     "*trace tramp" (mapcar #'list (mapcar #'buffer-name (buffer-list))))))
 
+;; Use `match-buffers' starting with Emacs 29.1.
 ;;;###tramp-autoload
 (defun tramp-list-remote-buffers ()
   "Return a list of all buffers with remote `default-directory'."
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index 5bd3dff3d21..7c10c6530e9 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -75,7 +75,7 @@
        (prog1 (setq xdg (concat (file-name-as-directory xdg) "emacs"))
         (make-directory xdg t))
      (eval (car (get 'temporary-file-directory 'standard-value)) t)))
-  "The default value of `temporary-file-directory'.")
+  "The default value of `temporary-file-directory' for Tramp.")
 
 (defsubst tramp-compat-make-temp-name ()
   "Generate a local temporary file name (compat function)."
diff --git a/lisp/org/org-mouse.el b/lisp/org/org-mouse.el
index e0671f3d7d5..9c9dfee51a1 100644
--- a/lisp/org/org-mouse.el
+++ b/lisp/org/org-mouse.el
@@ -859,6 +859,10 @@ This means, between the beginning of line and the point."
               (org-mouse-in-region-p (posn-point (event-start event))))
     (mouse-drag-region event)))
 
+;; This function conflicts with touch screen gestures as it relays
+;; events to `mouse-drag-region'.
+(put 'org-mouse-down-mouse 'ignored-mouse-command t)
+
 (add-hook 'org-mode-hook
           (lambda ()
             (setq org-mouse-context-menu-function #'org-mouse-context-menu)
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 61898620c8d..b3c48eb2c65 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -880,29 +880,36 @@ Return nil if NODE is not a defun node or doesn't have a 
name."
 (defun c-ts-mode--defun-valid-p (node)
   "Return non-nil if NODE is a valid defun node.
 Ie, NODE is not nested."
-  (or (c-ts-mode--emacs-defun-p node)
-      (not (or (and (member (treesit-node-type node)
-                            '("struct_specifier"
-                              "enum_specifier"
-                              "union_specifier"
-                              "declaration"))
-                    ;; If NODE's type is one of the above, make sure it is
-                    ;; top-level.
-                    (treesit-node-top-level
-                     node (rx (or "function_definition"
-                                  "type_definition"
-                                  "struct_specifier"
-                                  "enum_specifier"
-                                  "union_specifier"
-                                  "declaration"))))
-
-               (and (equal (treesit-node-type node) "declaration")
-                    ;; If NODE is a declaration, make sure it is not a
-                    ;; function declaration.
-                    (equal (treesit-node-type
-                            (treesit-node-child-by-field-name
-                             node "declarator"))
-                           "function_declarator"))))))
+  (let ((top-level-p (lambda (node)
+                       (not (treesit-node-top-level
+                             node (rx (or "function_definition"
+                                          "type_definition"
+                                          "struct_specifier"
+                                          "enum_specifier"
+                                          "union_specifier"
+                                          "declaration")))))))
+    (pcase (treesit-node-type node)
+      ;; The declaration part of a DEFUN.
+      ("expression_statement" (c-ts-mode--emacs-defun-p node))
+      ;; The body of a DEFUN.
+      ("compound_statement" (c-ts-mode--emacs-defun-body-p node))
+      ;; If NODE's type is one of these three, make sure it is
+      ;; top-level.
+      ((or "struct_specifier"
+           "enum_specifier"
+           "union_specifier")
+       (funcall top-level-p node))
+      ;; If NODE is a declaration, make sure it's not a function
+      ;; declaration (we only want function_definition) and is a
+      ;; top-level declaration.
+      ("declaration"
+       (and (not (equal (treesit-node-type
+                         (treesit-node-child-by-field-name
+                          node "declarator"))
+                        "function_declarator"))
+            (funcall top-level-p node)))
+      ;; Other types don't need further verification.
+      (_ t))))
 
 (defun c-ts-mode--defun-for-class-in-imenu-p (node)
   "Check if NODE is a valid entry for the Class subindex.
@@ -955,6 +962,11 @@ files using the DEFUN macro."
                t)
               "DEFUN")))
 
+(defun c-ts-mode--emacs-defun-body-p (node)
+  "Return non-nil if NODE is the function body of a DEFUN."
+  (and (equal (treesit-node-type node) "compound_statement")
+       (c-ts-mode--emacs-defun-p (treesit-node-prev-sibling node))))
+
 (defun c-ts-mode--emacs-defun-at-point (&optional range)
   "Return the defun node at point.
 
@@ -969,31 +981,18 @@ function returns the declaration node.
 If RANGE is non-nil, return (BEG . END) where BEG end END
 encloses the whole defun.  This is for when the entire defun
 is required, not just the declaration part for DEFUN."
-  (or (when-let ((node (treesit-defun-at-point)))
-        (if range
-            (cons (treesit-node-start node)
-                (treesit-node-end node))
-            node))
-      (and c-ts-mode-emacs-sources-support
-           (let ((candidate-1 ; For when point is in the DEFUN statement.
-                  (treesit-node-prev-sibling
-                   (treesit-node-top-level
-                    (treesit-node-at (point))
-                    "compound_statement")))
-                 (candidate-2 ; For when point is in the body.
-                  (treesit-node-top-level
-                   (treesit-node-at (point))
-                   "expression_statement")))
-             (when-let
-                 ((node (or (and (c-ts-mode--emacs-defun-p candidate-1)
-                                 candidate-1)
-                            (and (c-ts-mode--emacs-defun-p candidate-2)
-                                 candidate-2))))
-               (if range
-                   (cons (treesit-node-start node)
-                       (treesit-node-end
-                        (treesit-node-next-sibling node)))
-                   node))))))
+  (when-let* ((node (treesit-defun-at-point))
+              (defun-range (cons (treesit-node-start node)
+                                 (treesit-node-end node))))
+    ;; Make some adjustment for DEFUN.
+    (when c-ts-mode-emacs-sources-support
+      (cond ((c-ts-mode--emacs-defun-body-p node)
+             (setq node (treesit-node-prev-sibling node))
+             (setcar defun-range (treesit-node-start node)))
+            ((c-ts-mode--emacs-defun-p node)
+             (setcdr defun-range (treesit-node-end
+                                  (treesit-node-next-sibling node))))))
+    (if range defun-range node)))
 
 (defun c-ts-mode-indent-defun ()
   "Indent the current top-level declaration syntactically.
@@ -1111,13 +1110,19 @@ BEG and END are described in `treesit-range-rules'."
 
   ;; Navigation.
   (setq-local treesit-defun-type-regexp
-              (cons (regexp-opt '("function_definition"
-                                  "type_definition"
-                                  "struct_specifier"
-                                  "enum_specifier"
-                                  "union_specifier"
-                                  "class_specifier"
-                                  "namespace_definition"))
+              (cons (regexp-opt (append
+                                 '("function_definition"
+                                   "type_definition"
+                                   "struct_specifier"
+                                   "enum_specifier"
+                                   "union_specifier"
+                                   "class_specifier"
+                                   "namespace_definition")
+                                 (and c-ts-mode-emacs-sources-support
+                                      '(;; DEFUN.
+                                        "expression_statement"
+                                        ;; DEFUN body.
+                                        "compound_statement"))))
                     #'c-ts-mode--defun-valid-p))
   (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
   (setq-local treesit-defun-name-function #'c-ts-mode--defun-name)
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 5291efda175..37bb84ab5ba 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -45,6 +45,7 @@
 (declare-function treesit-node-start "treesit.c")
 (declare-function treesit-node-type "treesit.c")
 (declare-function treesit-node-child-by-field-name "treesit.c")
+(declare-function treesit-query-capture "treesit.c")
 
 (defgroup csharp nil
   "Major mode for editing C# code."
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index c7a031697f1..1d89b35aa2d 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3501,35 +3501,6 @@ Check if a node type is available, then return the right 
indent rules."
     "&&" "||" "!")
   "JavaScript operators for tree-sitter font-locking.")
 
-(defun js-jsx--treesit-font-lock-compatibility-bb1f97b ()
-  "Font lock rules helper, to handle different releases of 
tree-sitter-javascript.
-Check if a node type is available, then return the right font lock rules."
-  ;; handle commit bb1f97b
-  (condition-case nil
-      (progn (treesit-query-capture 'javascript '((member_expression) 
@capture))
-            '((jsx_opening_element
-               [(member_expression (identifier)) (identifier)]
-               @font-lock-function-call-face)
-
-              (jsx_closing_element
-               [(member_expression (identifier)) (identifier)]
-               @font-lock-function-call-face)
-
-              (jsx_self_closing_element
-               [(member_expression (identifier)) (identifier)]
-               @font-lock-function-call-face)))
-    (error '((jsx_opening_element
-             [(nested_identifier (identifier)) (identifier)]
-             @font-lock-function-call-face)
-
-            (jsx_closing_element
-             [(nested_identifier (identifier)) (identifier)]
-             @font-lock-function-call-face)
-
-            (jsx_self_closing_element
-             [(nested_identifier (identifier)) (identifier)]
-             @font-lock-function-call-face)))))
-
 (defvar js--treesit-font-lock-settings
   (treesit-font-lock-rules
 
@@ -3639,8 +3610,10 @@ Check if a node type is available, then return the right 
font lock rules."
 
    :language 'javascript
    :feature 'jsx
-   (append (js-jsx--treesit-font-lock-compatibility-bb1f97b)
-          '((jsx_attribute (property_identifier) @font-lock-constant-face)))
+   '((jsx_opening_element name: (_) @font-lock-function-call-face)
+     (jsx_closing_element name: (_) @font-lock-function-call-face)
+     (jsx_self_closing_element name: (_) @font-lock-function-call-face)
+     (jsx_attribute (property_identifier) @font-lock-constant-face))
 
    :language 'javascript
    :feature 'number
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 6f35b3cc1b1..ab7376b7dc6 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -989,6 +989,23 @@ pattern to search for."
     (read-regexp "Find regexp" (and sym (regexp-quote sym))
                  project-regexp-history-variable)))
 
+(defun project--find-default-from (filename project)
+  "Ensure FILENAME is in PROJECT.
+
+Usually, just return FILENAME.  But if
+`project-current-directory-override' is set, adjust it to be
+relative to PROJECT instead.
+
+This supports using a relative file name from the current buffer
+when switching projects with `project-switch-project' and then
+using a command like `project-find-file'."
+  (if-let (filename-proj (and project-current-directory-override
+                            (project-current nil default-directory)))
+      ;; file-name-concat requires Emacs 28+
+      (concat (file-name-as-directory (project-root project))
+              (file-relative-name filename (project-root filename-proj)))
+    filename))
+
 ;;;###autoload
 (defun project-find-file (&optional include-all)
   "Visit a file (with completion) in the current project.
@@ -1006,16 +1023,7 @@ for VCS directories listed in 
`vc-directory-exclusion-list'."
          (dirs (list root)))
     (project-find-file-in
      (or (thing-at-point 'filename)
-         (and buffer-file-name
-              (if-let (buffer-proj (and project-current-directory-override
-                                        (project-current nil 
default-directory)))
-                  ;; Allow using the relative file name of the current
-                  ;; buffer in "other project" as well.
-                  (let ((buffer-root (project-root buffer-proj)))
-                    ;; file-name-concat requires Emacs 28+
-                    (concat (file-name-as-directory root)
-                            (file-relative-name buffer-file-name buffer-root)))
-                buffer-file-name)))
+         (and buffer-file-name (project--find-default-from buffer-file-name 
pr)))
      dirs pr include-all)))
 
 ;;;###autoload
@@ -1023,17 +1031,23 @@ for VCS directories listed in 
`vc-directory-exclusion-list'."
   "Visit a file (with completion) in the current project or external roots.
 
 The filename at point (determined by `thing-at-point'), if any,
-is available as part of \"future history\".
+is available as part of \"future history\".  If none, the current
+buffer's file name is used.
 
 If INCLUDE-ALL is non-nil, or with prefix argument when called
 interactively, include all files under the project root, except
 for VCS directories listed in `vc-directory-exclusion-list'."
   (interactive "P")
+  (defvar project-file-history-behavior)
   (let* ((pr (project-current t))
          (dirs (cons
                 (project-root pr)
-                (project-external-roots pr))))
-    (project-find-file-in (thing-at-point 'filename) dirs pr include-all)))
+                (project-external-roots pr)))
+         (project-file-history-behavior t))
+    (project-find-file-in
+     (or (thing-at-point 'filename)
+         (and buffer-file-name (project--find-default-from buffer-file-name 
pr)))
+     dirs pr include-all)))
 
 (defcustom project-read-file-name-function #'project--read-file-cpd-relative
   "Function to call to read a file name from a list.
@@ -1046,6 +1060,28 @@ For the arguments list, see 
`project--read-file-cpd-relative'."
   :group 'project
   :version "27.1")
 
+(defcustom project-file-history-behavior t
+  "If `relativize', entries in `file-name-history' are adjusted.
+
+History entries shown in `project-find-file', `project-find-dir',
+(from `file-name-history') are adjusted to be relative to the
+current project root, instead of the project which added those
+paths.  This only affects history entries added by earlier calls
+to `project-find-file' or `project-find-dir'.
+
+This has the effect of sharing more history between projects."
+  :type '(choice (const t :tag "Default behavior")
+                 (const relativize :tag "Adjust to be relative to current"))
+  :group 'project
+  :version "30.1")
+
+(defun project--transplant-file-name (filename project)
+  (when-let ((old-root (get-text-property 0 'project filename)))
+    (abbreviate-file-name
+     (expand-file-name
+      (file-relative-name filename old-root)
+      (project-root project)))))
+
 (defun project--read-file-cpd-relative (prompt
                                         all-files &optional predicate
                                         hist mb-default)
@@ -1079,8 +1115,7 @@ by the user at will."
          (new-collection (project--file-completion-table substrings))
          (abbr-cpd (abbreviate-file-name common-parent-directory))
          (abbr-cpd-length (length abbr-cpd))
-         (relname (cl-letf ((history-add-new-input nil)
-                            ((symbol-value hist)
+         (relname (cl-letf (((symbol-value hist)
                              (mapcan
                               (lambda (s)
                                 (and (string-prefix-p abbr-cpd s)
@@ -1092,8 +1127,6 @@ by the user at will."
                                                      predicate
                                                      hist mb-default)))
          (absname (expand-file-name relname common-parent-directory)))
-    (when (and hist history-add-new-input)
-      (add-to-history hist (abbreviate-file-name absname)))
     absname))
 
 (defun project--read-file-absolute (prompt
@@ -1104,6 +1137,29 @@ by the user at will."
                                    predicate
                                    hist mb-default))
 
+(defun project--read-file-name ( project prompt
+                                 all-files &optional predicate
+                                 hist mb-default)
+  "Call `project-read-file-name-function' with appropriate history.
+
+Depending on `project-file-history-behavior', entries are made
+project-relative where possible."
+  (let ((file
+         (cl-letf ((history-add-new-input nil)
+                   ((symbol-value hist)
+                    (if (eq project-file-history-behavior 'relativize)
+                        (mapcar
+                         (lambda (f)
+                           (or (project--transplant-file-name f project) f))
+                         (symbol-value hist))
+                      (symbol-value hist))))
+           (funcall project-read-file-name-function
+                    prompt all-files predicate hist mb-default))))
+    (when (and hist history-add-new-input)
+      (add-to-history hist
+                      (propertize file 'project (project-root project))))
+    file))
+
 (defun project-find-file-in (suggested-filename dirs project &optional 
include-all)
   "Complete a file name in DIRS in PROJECT and visit the result.
 
@@ -1124,9 +1180,10 @@ directories listed in `vc-directory-exclusion-list'."
                dirs)
             (project-files project dirs)))
          (completion-ignore-case read-file-name-completion-ignore-case)
-         (file (funcall project-read-file-name-function
-                        "Find file" all-files nil 'file-name-history
-                        suggested-filename)))
+         (file (project--read-file-name
+                project "Find file"
+                all-files nil 'file-name-history
+                suggested-filename)))
     (if (string= file "")
         (user-error "You didn't specify the file")
       (find-file file))))
@@ -1147,7 +1204,10 @@ directories listed in `vc-directory-exclusion-list'."
 
 ;;;###autoload
 (defun project-find-dir ()
-  "Start Dired in a directory inside the current project."
+  "Start Dired in a directory inside the current project.
+
+The current buffer's `default-directory' is available as part of
+\"future history\"."
   (interactive)
   (let* ((project (project-current t))
          (all-files (project-files project))
@@ -1158,11 +1218,13 @@ directories listed in `vc-directory-exclusion-list'."
          ;; https://stackoverflow.com/a/50685235/615245 for possible
          ;; implementation.
          (all-dirs (mapcar #'file-name-directory all-files))
-         (dir (funcall project-read-file-name-function
-                       "Dired"
-                       ;; Some completion UIs show duplicates.
-                       (delete-dups all-dirs)
-                       nil 'file-name-history)))
+         (dir (project--read-file-name
+               project "Dired"
+               ;; Some completion UIs show duplicates.
+               (delete-dups all-dirs)
+               nil 'file-name-history
+               (and default-directory
+                    (project--find-default-from default-directory project)))))
     (dired dir)))
 
 ;;;###autoload
@@ -1597,7 +1659,12 @@ With some possible metadata (to be decided).")
           (when (file-exists-p filename)
             (with-temp-buffer
               (insert-file-contents filename)
-              (read (current-buffer)))))
+              (mapcar
+               (lambda (elem)
+                 (let ((name (car elem)))
+                   (list (if (file-remote-p name) name
+                           (abbreviate-file-name name)))))
+               (read (current-buffer))))))
     (unless (seq-every-p
              (lambda (elt) (stringp (car-safe elt)))
              project--list)
@@ -1617,7 +1684,12 @@ With some possible metadata (to be decided).")
       (insert ";;; -*- lisp-data -*-\n")
       (let ((print-length nil)
             (print-level nil))
-        (pp project--list (current-buffer)))
+        (pp (mapcar (lambda (elem)
+                      (let ((name (car elem)))
+                        (list (if (file-remote-p name) name
+                                (expand-file-name name)))))
+                    project--list)
+            (current-buffer)))
       (write-region nil nil filename nil 'silent))))
 
 ;;;###autoload
@@ -1626,7 +1698,7 @@ With some possible metadata (to be decided).")
 Save the result in `project-list-file' if the list of projects
 has changed, and NO-WRITE is nil."
   (project--ensure-read-project-list)
-  (let ((dir (project-root pr)))
+  (let ((dir (abbreviate-file-name (project-root pr))))
     (unless (equal (caar project--list) dir)
       (dolist (ent project--list)
         (when (equal dir (car ent))
@@ -1642,7 +1714,7 @@ result in `project-list-file'.  Announce the project's 
removal
 from the list using REPORT-MESSAGE, which is a format string
 passed to `message' as its first argument."
   (project--ensure-read-project-list)
-  (when-let ((ent (assoc project-root project--list)))
+  (when-let ((ent (assoc (abbreviate-file-name project-root) project--list)))
     (setq project--list (delq ent project--list))
     (message report-message project-root)
     (project--write-project-list)))
@@ -1832,6 +1904,17 @@ listed in the dispatch menu produced from 
`project-switch-commands'."
   :group 'project
   :version "28.1")
 
+(defcustom project-key-prompt-style (if (facep 'help-key-binding)
+                                        t
+                                      'brackets)
+  "Which presentation to use when asking to choose a command by key.
+
+When `brackets', use text brackets and `bold' for the character.
+Otherwise, use the face `help-key-binding' in the prompt."
+  :type 'boolean
+  :group 'project
+  :version "30.1")
+
 (defun project--keymap-prompt ()
   "Return a prompt for the project switching dispatch menu."
   (mapconcat
@@ -1844,7 +1927,7 @@ listed in the dispatch menu produced from 
`project-switch-commands'."
      (let ((key (if key
                     (vector key)
                   (where-is-internal cmd (list project-prefix-map) t))))
-       (if (facep 'help-key-binding)
+       (if (not (eq project-key-prompt-style 'brackets))
            (format "%s %s"
                    (propertize (key-description key) 'face 'help-key-binding)
                    label)
diff --git a/lisp/progmodes/vera-mode.el b/lisp/progmodes/vera-mode.el
index 07d3ef07d7b..d4f8f71b789 100644
--- a/lisp/progmodes/vera-mode.el
+++ b/lisp/progmodes/vera-mode.el
@@ -5,7 +5,7 @@
 ;; Author:      Reto Zimmermann <reto@gnu.org>
 ;; Version:     2.28
 ;; Keywords:    languages vera
-;; WWW:         https://guest.iis.ee.ethz.ch/~zimmi/emacs/vera-mode.html
+;; URL:         https://iis-people.ee.ethz.ch/~zimmi/emacs/vera-mode.html
 
 ;; Yoni Rabkin <yoni@rabkins.net> contacted the maintainer of this
 ;; file on 18/3/2008, and the maintainer agreed that when a bug is
diff --git a/lisp/progmodes/vhdl-mode.el b/lisp/progmodes/vhdl-mode.el
index 77d862f1a17..8d0a10c0918 100644
--- a/lisp/progmodes/vhdl-mode.el
+++ b/lisp/progmodes/vhdl-mode.el
@@ -6,7 +6,7 @@
 ;;              Rodney J. Whitby <software.vhdl-mode@rwhitby.net>
 ;; Maintainer:  Reto Zimmermann <reto@gnu.org>
 ;; Keywords:    languages vhdl
-;; WWW:         https://guest.iis.ee.ethz.ch/~zimmi/emacs/vhdl-mode.html
+;; URL:         https://iis-people.ee.ethz.ch/~zimmi/emacs/vhdl-mode.html
 
 ;; Yoni Rabkin <yoni@rabkins.net> contacted the maintainer of this
 ;; file on 18/3/2008, and the maintainer agreed that when a bug is
diff --git a/lisp/replace.el b/lisp/replace.el
index 1555731f6e3..eeac734f3bd 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -417,8 +417,9 @@ Replacement transfers the case pattern of the old text to 
the
 new text, if both `case-fold-search' and `case-replace' are
 non-nil and FROM-STRING has no uppercase letters.
 \(Transferring the case pattern means that if the old text
-matched is all caps, or capitalized, then its replacement is
-respectively upcased or capitalized.)
+matched is all caps, or all of its words are capitalized, then its
+replacement is respectively upcased or capitalized.  For more
+details about this, see `replace-match'.)
 
 Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
 ignore hidden matches if `search-invisible' is nil, and ignore more
@@ -492,8 +493,9 @@ there are uppercase letters in REGEXP.
 Replacement transfers the case pattern of the old text to the new
 text, if both `case-fold-search' and `case-replace' are non-nil
 and REGEXP has no uppercase letters.  (Transferring the case pattern
-means that if the old text matched is all caps, or capitalized,
-then its replacement is respectively upcased or capitalized.)
+means that if the old text matched is all caps, or all of its words
+are capitalized, then its replacement is respectively upcased or
+capitalized.  For more details about this, see `replace-match'.)
 
 Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
 ignore hidden matches if `search-invisible' is nil, and ignore more
diff --git a/lisp/simple.el b/lisp/simple.el
index 1bc35e87554..05a3c4b93d6 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -10792,10 +10792,13 @@ warning using STRING as the message.")
 
 ;;; Generic dispatcher commands
 
-;; Macro `define-alternatives' is used to create generic commands.
-;; Generic commands are these (like web, mail, news, encrypt, irc, etc.)
-;; that can have different alternative implementations where choosing
-;; among them is exclusively a matter of user preference.
+;; Macro `define-alternatives' can be used to create generic commands.
+;; Generic commands are commands that can have different alternative
+;; implementations, and choosing among them is the matter of user
+;; preference in each case.  For example, you could have a generic
+;; command `open' capable of "opening" a text file, a URL, a
+;; directory, or a binary file, and each of these alternatives would
+;; invoke a different Emacs function.
 
 ;; (define-alternatives COMMAND) creates a new interactive command
 ;; M-x COMMAND and a customizable variable COMMAND-alternatives.
@@ -10805,26 +10808,38 @@ warning using STRING as the message.")
 ;; ;;;###autoload (push '("My impl name" . my-impl-symbol) COMMAND-alternatives
 
 (defmacro define-alternatives (command &rest customizations)
-  "Define the new command `COMMAND'.
+  "Define a new generic COMMAND which can have several implementations.
 
-The argument `COMMAND' should be a symbol.
+The argument `COMMAND' should be an unquoted symbol.
 
 Running `\\[execute-extended-command] COMMAND RET' for \
-the first time prompts for which
-alternative to use and records the selected command as a custom
-variable.
+the first time prompts for the
+alternative implementation to use and records the selected alternative.
+Thereafter, `\\[execute-extended-command] COMMAND RET' will \
+automatically invoke the recorded selection.
 
 Running `\\[universal-argument] \\[execute-extended-command] COMMAND RET' \
-prompts again for an alternative
-and overwrites the previous choice.
-
-The variable `COMMAND-alternatives' contains an alist with
-alternative implementations of COMMAND.  `define-alternatives'
-does not have any effect until this variable is set.
-
-CUSTOMIZATIONS, if non-nil, should be composed of alternating
-`defcustom' keywords and values to add to the declaration of
-`COMMAND-alternatives' (typically :group and :version)."
+again prompts for an alternative
+and overwrites the previous selection.
+
+The macro creates a `defcustom' named `COMMAND-alternatives'.
+CUSTOMIZATIONS, if non-nil, should be pairs of `defcustom'
+keywords and values to add to the definition of that `defcustom';
+typically, these keywords will be :group and :version with the
+appropriate values.
+
+To be useful, the value of `COMMAND-alternatives' should be an
+alist describing the alternative implementations of COMMAND.
+The elements of this alist should be of the form
+  (ALTERNATIVE-NAME . FUNCTION)
+where ALTERNATIVE-NAME is the name of the alternative to be shown
+to the user as a selectable alternative, and FUNCTION is the
+interactive function to call which implements that alternative.
+The variable could be populated with associations describing the
+alternatives either before or after invoking `define-alternatives';
+if the variable is not defined when `define-alternatives' is invoked,
+the macro will create it with a nil value, and your Lisp program
+should then populate it."
   (declare (indent defun))
   (let* ((command-name (symbol-name command))
          (varalt-name (concat command-name "-alternatives"))
diff --git a/lisp/subr.el b/lisp/subr.el
index f6332ce35e6..47fcbc2f317 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -1993,10 +1993,14 @@ instead; it will indirectly limit the specpdl stack 
size as well.")
                         'native-comp-enable-subr-trampolines
                         "29.1")
 
+(defvaralias 'comp-enable-subr-trampolines 
'native-comp-enable-subr-trampolines)
+
 (make-obsolete-variable 'native-comp-deferred-compilation
                         'native-comp-jit-compilation
                         "29.1")
 
+(defvaralias 'native-comp-deferred-compilation 'native-comp-jit-compilation)
+
 
 ;;;; Alternate names for functions - these are not being phased out.
 
diff --git a/lisp/textmodes/bibtex.el b/lisp/textmodes/bibtex.el
index 394f80f47ee..32d2786b86c 100644
--- a/lisp/textmodes/bibtex.el
+++ b/lisp/textmodes/bibtex.el
@@ -1845,7 +1845,7 @@ Initialized by `bibtex-set-dialect'.")
   ;; Assume that field names begin at the beginning of a line.
   (concat "^[ \t]*"
           (regexp-opt (delete-dups (mapcar #'caar bibtex-generate-url-list)) t)
-          "[ \t]*=[ \t]*")
+          "[ \t\n]*=[ \t\n]*")
   "Regexp for `bibtex-font-lock-url' derived from `bibtex-generate-url-list'.")
 
 (defvar bibtex-string-empty-key nil
diff --git a/lisp/vc/vc-rcs.el b/lisp/vc/vc-rcs.el
index c2112b76ad3..3d6907cbec1 100644
--- a/lisp/vc/vc-rcs.el
+++ b/lisp/vc/vc-rcs.el
@@ -864,14 +864,15 @@ and CVS."
 (defvar vc-rcs-rcs2log-program
   (let (exe)
     (cond ((file-executable-p
-            (setq exe (expand-file-name "rcs2log" exec-directory)))
+            (setq exe (expand-file-name rcs2log-program-name
+                                        exec-directory)))
            exe)
           ;; In the unlikely event that someone is running an
           ;; uninstalled Emacs and wants to do something RCS-related.
           ((file-executable-p
             (setq exe (expand-file-name "lib-src/rcs2log" source-directory)))
            exe)
-          (t "rcs2log")))
+          (t rcs2log-program-name)))
   "Path to the `rcs2log' program (normally in `exec-directory').")
 
 (autoload 'vc-buffer-sync "vc-dispatcher")
diff --git a/lisp/window.el b/lisp/window.el
index d91bbabc010..b0970cfb064 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -2121,12 +2121,16 @@ remapped (see `face-remapping-alist'), the function 
returns the
 information for the remapped face."
    (with-selected-window (window-normalize-window window t)
      (if (display-multi-font-p)
-        (let* ((face (if face face 'default))
-               (info (font-info (face-font face)))
-               (width (aref info 11)))
-          (if (> width 0)
-             width
-            (aref info 10)))
+         ;; Opening the XLFD returned by `font-info' may be
+         ;; unsuccessful.  Use `frame-char-width' as a recourse if
+         ;; such a situation transpires.
+         (or (when-let* ((face (if face face 'default))
+                        (info (font-info (face-font face)))
+                        (width (aref info 11)))
+              (if (> width 0)
+                  width
+                (aref info 10)))
+             (frame-char-width))
        (frame-char-width))))
 
 (defun window-font-height (&optional window face)
@@ -2138,9 +2142,10 @@ remapped (see `face-remapping-alist'), the function 
returns the
 information for the remapped face."
    (with-selected-window (window-normalize-window window t)
      (if (display-multi-font-p)
-        (let* ((face (if face face 'default))
-               (info (font-info (face-font face))))
-          (aref info 3))
+        (or (when-let* ((face (if face face 'default))
+                        (info (font-info (face-font face))))
+              (aref info 3))
+             (frame-char-height))
        (frame-char-height))))
 
 (defvar overflow-newline-into-fringe)
diff --git a/src/androidterm.c b/src/androidterm.c
index 473bea76ef5..a60dd50e5db 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -4932,14 +4932,16 @@ android_text_to_string (JNIEnv *env, char *buffer, 
ptrdiff_t n,
       eassert (CHAR_HEAD_P (*buffer));
       encoded = STRING_CHAR ((unsigned char *) buffer);
 
-      /* Now figure out how to save ENCODED into the string.
-         Emacs operates on multibyte characters, not UTF-16
-         characters with surrogate pairs as Android does.
+      /* Now establish how to save ENCODED into the string.
+         Emacs operates on multibyte characters, not UTF-16 characters
+         with surrogate pairs as Android does.
 
-         However, character positions in Java are represented in 2
-         byte units, meaning that the text position reported to
-         Android can become out of sync if characters are found in a
-         buffer that require surrogate pairs.
+         However, character positions in Java are represented as
+         character (rather than codepoint) indices into UTF-16
+         strings, meaning that text positions reported to Android can
+         become decoupled from their actual values if the text
+         returned incorporates characters that must be encoded as
+         surrogate pairs.
 
          The hack used by Emacs is to simply replace each multibyte
          character that doesn't fit in a jchar with the NULL
@@ -5940,9 +5942,9 @@ NATIVE_NAME (takeSnapshot) (JNIEnv *env, jobject object, 
jshort window)
 
 #ifdef __clang__
 #pragma clang diagnostic pop
-#else
+#else /* GCC */
 #pragma GCC diagnostic pop
-#endif
+#endif /* __clang__ */
 
 
 
@@ -5991,11 +5993,11 @@ android_update_selection (struct frame *f, struct 
window *w)
          ? min (w->last_mark, TYPE_MAXIMUM (jint))
          : point);
 
-  /* Send the update.  Android doesn't have a concept of ``point'' and
-     ``mark''; instead, it only has a selection, where the start of
-     the selection is less than or equal to the end.  Also, convert
-     the indices from 1-based Emacs indices to 0-based Android
-     ones.  */
+  /* Send the update.  Android doesn't employ a concept of ``point''
+     and ``mark''; instead, it only has a selection, where the start
+     of the selection is less than or equal to the end, and the region
+     is ``active'' when those two values differ.  Also, convert the
+     indices from 1-based Emacs indices to 0-based Android ones.  */
   android_update_ic (FRAME_ANDROID_WINDOW (f), min (point, mark) - 1,
                     max (point, mark) - 1, start, end);
 
@@ -6066,9 +6068,10 @@ android_reset_conversion (struct frame *f)
 
   /* Reset the input method.
 
-     Pick an appropriate ``input mode'' based on whether or not the
-     minibuffer window is selected; this controls whether or not
-     ``RET'' inserts a newline or sends an actual key event.  */
+     Select an appropriate ``input mode'' based on whether or not the
+     minibuffer window is selected, which in turn affects if ``RET''
+     inserts a newline or sends an editor action Emacs transforms into
+     a key event (refer to `performEditorAction'.)  */
 
   w = XWINDOW (f->selected_window);
   buffer = XBUFFER (WINDOW_BUFFER (w));
@@ -6360,7 +6363,7 @@ android_set_build_fingerprint (void)
 {
 #ifdef ANDROID_STUBIFY
   Vandroid_build_fingerprint = Qnil;
-#else
+#else /* !ANDROID_STUBIFY */
   jclass class;
   jfieldID field;
   jobject string;
@@ -6378,7 +6381,7 @@ android_set_build_fingerprint (void)
   else
     {
       /* Obtain Build.FINGERPRINT.  Clear exceptions after each query;
-        JNI can't find Build.FINGERPRIN on some systems.  */
+        JNI can't find Build.FINGERPRINT on some systems.  */
 
       class = (*android_java_env)->FindClass (android_java_env,
                                              "android/os/Build");
@@ -6415,7 +6418,7 @@ android_set_build_fingerprint (void)
       (*android_java_env)->ReleaseStringUTFChars (android_java_env,
                                                  string, data);
 
-      /* Now obtain Build.MANUFACTURER.  */
+      /* Now retrieve Build.MANUFACTURER.  */
 
       ANDROID_DELETE_LOCAL_REF (string);
       string = NULL;
@@ -6462,7 +6465,7 @@ android_set_build_fingerprint (void)
 
   Vandroid_build_fingerprint = Qnil;
   Vandroid_build_manufacturer = Qnil;
-#endif
+#endif /* ANDROID_STUBIFY */
 }
 
 void
diff --git a/src/callproc.c b/src/callproc.c
index dc37dfdc01f..082c65c4f14 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -2216,6 +2216,17 @@ the system.  */);
   Vebrowse_program_name = build_pure_c_string ("libebrowse.so");
 #endif
 
+  DEFVAR_LISP ("rcs2log-program-name", Vrcs2log_program_name,
+    doc: /* Name of the `rcs2log' program distributed with Emacs.
+Use this instead of calling `rcs2log' directly, as `rcs2log'
+may have been renamed to comply with executable naming restrictions on
+the system.  */);
+#if !defined HAVE_ANDROID || defined ANDROID_STUBIFY
+  Vrcs2log_program_name = build_pure_c_string ("rcs2log");
+#else /* HAVE_ANDROID && !ANDROID_STUBIFY */
+  Vrcs2log_program_name = build_pure_c_string ("librcs2log.so");
+#endif /* !HAVE_ANDROID || ANDROID_STUBIFY */
+
   defsubr (&Scall_process);
   defsubr (&Sgetenv_internal);
   defsubr (&Scall_process_region);
diff --git a/src/dispnew.c b/src/dispnew.c
index 02388bcef2b..d6a27ac29ec 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -6849,6 +6849,7 @@ The value is a symbol:
  `pc' for a direct-write MS-DOS frame.
  `pgtk' for an Emacs frame using pure GTK facilities.
  `haiku' for an Emacs frame running in Haiku.
+ `android' for an Emacs frame running in Android.
 
 Use of this variable as a boolean is deprecated.  Instead,
 use `display-graphic-p' or any of the other `display-*-p'
diff --git a/src/fns.c b/src/fns.c
index 766216bd1a8..3178b08aef0 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -746,7 +746,8 @@ usage: (vconcat &rest SEQUENCES)   */)
 DEFUN ("copy-sequence", Fcopy_sequence, Scopy_sequence, 1, 1, 0,
        doc: /* Return a copy of a list, vector, string, char-table or record.
 The elements of a list, vector or record are not copied; they are
-shared with the original.
+shared with the original.  See Info node `(elisp) Sequence Functions'
+for more details about this sharing and its effects.
 If the original sequence is empty, this function may return
 the same empty object instead of its copy.  */)
   (Lisp_Object arg)
diff --git a/src/font.c b/src/font.c
index 99247efb001..58850b010e8 100644
--- a/src/font.c
+++ b/src/font.c
@@ -1875,7 +1875,11 @@ font_rescale_ratio (Lisp_Object font_entity)
            {
              if (NILP (name))
                name = Ffont_xlfd_name (font_entity, Qnil);
-             if (fast_string_match_ignore_case (XCAR (elt), name) >= 0)
+
+             /* N.B. that `name' is set to nil if the resulting XLFD
+                is too long.  */
+             if (!NILP (name)
+                 && fast_string_match_ignore_case (XCAR (elt), name) >= 0)
                return XFLOAT_DATA (XCDR (elt));
            }
          else if (FONT_SPEC_P (XCAR (elt)))
diff --git a/src/frame.c b/src/frame.c
index da00cbf4bce..4be9f06bd3c 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -282,7 +282,7 @@ The value is a symbol:
  `pc' for a direct-write MS-DOS frame.
  `pgtk' for an Emacs frame using pure GTK facilities.
  `haiku' for an Emacs frame running in Haiku.
- `android' for an Emacs frame running in Android/
+ `android' for an Emacs frame running in Android.
 
 FRAME defaults to the currently selected frame.
 
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index d5649e4d2ce..12a84687180 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -3315,9 +3315,7 @@ class EmacsFilePanelCallbackLooper : public BLooper
              {
                str_buf = (char *) alloca (std::strlen (str_path)
                                           + std::strlen (name) + 2);
-               snprintf (str_buf, std::strlen (str_path)
-                         + std::strlen (name) + 2, "%s/%s",
-                         str_path, name);
+               sprintf (str_buf, "%s/%s", str_path, name);
                file_name = strdup (str_buf);
              }
          }
diff --git a/src/search.c b/src/search.c
index 3edfc0bc1a8..742a78cb0cd 100644
--- a/src/search.c
+++ b/src/search.c
@@ -2363,7 +2363,9 @@ the replacement text.  Otherwise, maybe capitalize the 
whole text, or
 maybe just word initials, based on the replaced text.  If the replaced
 text has only capital letters and has at least one multiletter word,
 convert NEWTEXT to all caps.  Otherwise if all words are capitalized
-in the replaced text, capitalize each word in NEWTEXT.
+in the replaced text, capitalize each word in NEWTEXT.  Note that
+what exactly is a word is determined by the syntax tables in effect
+in the current buffer.
 
 If optional third arg LITERAL is non-nil, insert NEWTEXT literally.
 Otherwise treat `\\' as special:
diff --git a/src/sfnt.c b/src/sfnt.c
index 14e353013cd..87a11019b13 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -432,7 +432,7 @@ sfnt_read_cmap_format_4 (int fd,
   int seg_count, i;
 
   min_bytes = SFNT_ENDOF (struct sfnt_cmap_format_4,
-                         entry_selector, uint16_t);
+                         range_shift, uint16_t);
 
   /* Check that the length is at least min_bytes.  */
   if (header->length < min_bytes)
@@ -460,6 +460,7 @@ sfnt_read_cmap_format_4 (int fd,
   sfnt_swap16 (&format4->seg_count_x2);
   sfnt_swap16 (&format4->search_range);
   sfnt_swap16 (&format4->entry_selector);
+  sfnt_swap16 (&format4->range_shift);
 
   /* Get the number of segments to read.  */
   seg_count = format4->seg_count_x2 / 2;
@@ -467,7 +468,7 @@ sfnt_read_cmap_format_4 (int fd,
   /* Now calculate whether or not the size is sufficiently large.  */
   bytes_minus_format4
     = format4->length - SFNT_ENDOF (struct sfnt_cmap_format_4,
-                                   entry_selector, uint16_t);
+                                   range_shift, uint16_t);
   variable_size = (seg_count * sizeof *format4->end_code
                   + sizeof *format4->reserved_pad
                   + seg_count * sizeof *format4->start_code
@@ -1222,27 +1223,6 @@ sfnt_lookup_glyph_4 (sfnt_char character,
   if (glyph)
     return glyph;
 
-  /* Droid Sans Mono has overlapping segments in its format 4 cmap
-     subtable where the first segment's end code is 32, while the
-     second segment's start code is also 32.  The TrueType Reference
-     Manual says that mapping should begin by searching for the first
-     segment whose end code is greater than or equal to the character
-     being indexed, but that results in the first subtable being
-     found, which doesn't work, while the second table does.  Try to
-     detect this situation and use the second table if possible.  */
-
-  if (!glyph
-      /* The character being looked up is the current segment's end
-        code.  */
-      && code == format4->end_code[segment]
-      /* There is an additional segment.  */
-      && segment + 1 < format4->seg_count_x2 / 2
-      /* That segment's start code is the same as this segment's end
-        code.  */
-      && format4->start_code[segment + 1] == format4->end_code[segment])
-    /* Try the second segment.  */
-    return sfnt_lookup_glyph_4_1 (character, segment + 1, format4);
-
   /* Fail.  */
   return 0;
 }
@@ -1262,6 +1242,19 @@ sfnt_lookup_glyph_6 (sfnt_char character,
   return format6->glyph_index_array[character - format6->first_code];
 }
 
+/* Compare the sfnt_char A with B's end code.  Employed to bisect
+   through a format 8 or 12 table.  */
+
+static int
+sfnt_compare_char (const void *a, const void *b)
+{
+  struct sfnt_cmap_format_8_or_12_group *group;
+
+  group = (struct sfnt_cmap_format_8_or_12_group *) b;
+
+  return ((int) *((sfnt_char *) a)) - group->end_char_code;
+}
+
 /* Look up the glyph corresponding to CHARACTER in the format 8 cmap
    FORMAT8.  Return 0 if no glyph was found.  */
 
@@ -1270,10 +1263,35 @@ sfnt_lookup_glyph_8 (sfnt_char character,
                     struct sfnt_cmap_format_8 *format8)
 {
   uint32_t i;
+  struct sfnt_cmap_format_8_or_12_group *group;
 
   if (character > 0xffffffff)
     return 0;
 
+  if (format8->num_groups > 64)
+    {
+      /* This table is large, likely supplied by a CJK or similar
+        font.  Perform a binary search.  */
+
+      /* Find the group whose END_CHAR_CODE is greater than or equal
+        to CHARACTER.  */
+
+      group = sfnt_bsearch_above (&character, format8->groups,
+                                 format8->num_groups,
+                                 sizeof format8->groups[0],
+                                 sfnt_compare_char);
+
+      if (group->start_char_code > character)
+       /* No glyph matches this group.  */
+       return 0;
+
+      /* Otherwise, use this group to map the character to a
+        glyph.  */
+      return (group->start_glyph_code
+             + character
+             - group->start_char_code);
+    }
+
   for (i = 0; i < format8->num_groups; ++i)
     {
       if (format8->groups[i].start_char_code <= character
@@ -1294,10 +1312,35 @@ sfnt_lookup_glyph_12 (sfnt_char character,
                      struct sfnt_cmap_format_12 *format12)
 {
   uint32_t i;
+  struct sfnt_cmap_format_8_or_12_group *group;
 
   if (character > 0xffffffff)
     return 0;
 
+  if (format12->num_groups > 64)
+    {
+      /* This table is large, likely supplied by a CJK or similar
+        font.  Perform a binary search.  */
+
+      /* Find the group whose END_CHAR_CODE is greater than or equal
+        to CHARACTER.  */
+
+      group = sfnt_bsearch_above (&character, format12->groups,
+                                 format12->num_groups,
+                                 sizeof format12->groups[0],
+                                 sfnt_compare_char);
+
+      if (group->start_char_code > character)
+       /* No glyph matches this group.  */
+       return 0;
+
+      /* Otherwise, use this group to map the character to a
+        glyph.  */
+      return (group->start_glyph_code
+             + character
+             - group->start_char_code);
+    }
+
   for (i = 0; i < format12->num_groups; ++i)
     {
       if (format12->groups[i].start_char_code <= character
@@ -1971,7 +2014,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
          /* The next byte is a delta to apply to the previous
             value.  Make sure it is in bounds.  */
 
-         if (vec_start + 1 >= glyf->glyphs + glyf->size)
+         if (vec_start + 1 > glyf->glyphs + glyf->size)
            {
              glyph->simple = NULL;
              xfree (simple);
@@ -1988,7 +2031,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
          /* The next word is a delta to apply to the previous value.
             Make sure it is in bounds.  */
 
-         if (vec_start + 2 >= glyf->glyphs + glyf->size)
+         if (vec_start + 2 > glyf->glyphs + glyf->size)
            {
              glyph->simple = NULL;
              xfree (simple);
@@ -2023,7 +2066,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
          /* The next byte is a delta to apply to the previous
             value.  Make sure it is in bounds.  */
 
-         if (vec_start + 1 >= glyf->glyphs + glyf->size)
+         if (vec_start + 1 > glyf->glyphs + glyf->size)
            {
              glyph->simple = NULL;
              xfree (simple);
@@ -2040,7 +2083,7 @@ sfnt_read_simple_glyph (struct sfnt_glyph *glyph,
          /* The next word is a delta to apply to the previous value.
             Make sure it is in bounds.  */
 
-         if (vec_start + 2 >= glyf->glyphs + glyf->size)
+         if (vec_start + 2 > glyf->glyphs + glyf->size)
            {
              glyph->simple = NULL;
              xfree (simple);
@@ -11828,7 +11871,7 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph 
*glyph,
          /* The offset is determined by matching a point location in
             a preceeding component with a point location in the
             current component.  The index of the point in the
-            previous component can be determined by adding
+            previous component is established by adding
             component->argument1.a or component->argument1.c to
             point.  argument2 contains the index of the point in the
             current component.  */
@@ -11857,30 +11900,29 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph 
*glyph,
 
          if (!subglyph->compound)
            {
+             /* Detect invalid child anchor points within simple
+                glyphs in advance.  */
+
              if (point2 >= subglyph->simple->number_of_points + 2)
                {
-                 /* If POINT2 is placed within a phantom point, use
-                    that.  */
-
                  if (need_free)
                    free_glyph (subglyph, dcontext);
 
                  return "Invalid component anchor point";
                }
+           }
 
-             /* First, set offsets to 0, because it is not yet
-                possible to ascertain the position of the anchor
-                point in the child.  That position cannot be
-                established prior to the completion of
-                grid-fitting.  */
-             x = 0;
-             y = 0;
+         /* First, set offsets to 0, because it is not yet possible
+            to ascertain the position of the anchor point in the
+            child.  That position cannot be established prior to the
+            completion of grid-fitting.  */
+         x = 0;
+         y = 0;
 
-             /* Set a flag which indicates that offsets must be
-                resolved from the child glyph after it is loaded, but
-                before it is incorporated into the parent glyph.  */
-             defer_offsets = true;
-           }
+         /* Set a flag which indicates that offsets must be resolved
+            from the child glyph after it is loaded, but before it is
+            incorporated into the parent glyph.  */
+         defer_offsets = true;
        }
 
       /* Obtain the glyph metrics.  If doing so fails, then cancel
@@ -13146,7 +13188,8 @@ sfnt_read_gvar_table (int fd, struct 
sfnt_offset_subtable *subtable)
 
   /* Start reading shared coordinates.  */
 
-  gvar->global_coords = ((sfnt_f2dot14 *) ((char *) gvar + off_size));
+  gvar->global_coords = ((sfnt_f2dot14 *) ((char *) (gvar + 1)
+                                          + off_size));
 
   if (gvar->shared_coord_count)
     {
@@ -13161,7 +13204,7 @@ sfnt_read_gvar_table (int fd, struct 
sfnt_offset_subtable *subtable)
          != coordinate_size)
        goto bail;
 
-      for (i = 0; i <= coordinate_size / sizeof *gvar->global_coords; ++i)
+      for (i = 0; i < coordinate_size / sizeof *gvar->global_coords; ++i)
        sfnt_swap16 (&gvar->global_coords[i]);
     }
 
diff --git a/src/sfnt.h b/src/sfnt.h
index 0fb67e918a6..1a6b2209abc 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -364,6 +364,9 @@ struct sfnt_cmap_format_4
   /* log2(searchRange/2) */
   uint16_t entry_selector;
 
+  /* (2 * segCount) - searchRange */
+  uint16_t range_shift;
+
   /* Variable-length data.  */
   uint16_t *end_code;
   uint16_t *reserved_pad;
diff --git a/src/sfntfont.c b/src/sfntfont.c
index c48339b6b66..f2dc05c886e 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -322,11 +322,30 @@ sfnt_decode_family_style (struct sfnt_name_table *name,
   struct sfnt_name_record family_rec, style_rec;
   unsigned char *family_data, *style_data;
 
-  family_data = sfnt_find_name (name, SFNT_NAME_FONT_FAMILY,
+  /* Because MS-Windows is incapable of treating font families
+     comprising more than four styles correctly, the TrueType
+     specification incorporates additional PREFERRED_FAMILY and
+     PREFERRED_SUBFAMILY name resources that are meant to be consulted
+     over the traditional family and subfamily resources.  When
+     present within fonts supplying unusual styles, these names hold
+     the ``actual'' typographic family and style of the font, in lieu
+     of the font family with the style affixed to the front and
+     Regular.  */
+
+  family_data = sfnt_find_name (name, SFNT_NAME_PREFERRED_FAMILY,
                                &family_rec);
-  style_data = sfnt_find_name (name, SFNT_NAME_FONT_SUBFAMILY,
+
+  if (!family_data)
+    family_data = sfnt_find_name (name, SFNT_NAME_FONT_FAMILY,
+                                 &family_rec);
+
+  style_data = sfnt_find_name (name, SFNT_NAME_PREFERRED_SUBFAMILY,
                               &style_rec);
 
+  if (!style_data)
+    style_data = sfnt_find_name (name, SFNT_NAME_FONT_SUBFAMILY,
+                                &style_rec);
+
   if (!family_data || !style_data)
     return 1;
 
@@ -834,6 +853,9 @@ sfnt_grok_registry (int fd, struct sfnt_font_desc *desc,
    newer font description DESC, and should be removed from the list of
    system fonts.
 
+   If both PREV and DESC are variable fonts, remove styles within PREV
+   that overlap with DESC and return false.
+
    If PREV is a variable font, potentially adjust its list of
    instances.  */
 
@@ -841,8 +863,8 @@ static bool
 sfnt_replace_fonts_p (struct sfnt_font_desc *prev,
                      struct sfnt_font_desc *desc)
 {
-  int i, width, weight, slant, count_instance;
-  Lisp_Object tem;
+  int i, j, width, weight, slant, count_instance;
+  Lisp_Object tem, tem1;
   bool family_equal_p;
 
   family_equal_p = !NILP (Fstring_equal (prev->family,
@@ -851,7 +873,54 @@ sfnt_replace_fonts_p (struct sfnt_font_desc *prev,
   if ((!NILP (desc->instances)
        || !NILP (Fstring_equal (prev->style, desc->style)))
       && family_equal_p)
-    return true;
+    {
+      /* If both inputs are GX fonts...  */
+      if (!NILP (desc->instances) && !NILP (prev->instances))
+       {
+         /* ...iterate over each of the styles provided by PREV.  If
+            they match any styles within DESC, remove the old style
+            from PREV.  */
+
+         count_instance = 0;
+         for (i = 0; i < ASIZE (prev->instances); ++i)
+           {
+             tem = AREF (prev->instances, i);
+
+             if (NILP (tem))
+               continue;
+
+             for (j = 0; j < ASIZE (desc->instances); ++j)
+               {
+                 tem1 = AREF (desc->instances, j);
+
+                 if (NILP (tem1))
+                   continue;
+
+                 if (!NILP (Fequal (tem1, tem)))
+                   {
+                     /* tem1 is identical to tem, so opt for it over
+                        tem.  */
+                     ASET (prev->instances, i, Qnil);
+                     goto next;
+                   }
+               }
+
+             /* Increment the number of instances remaining within
+                PREV.  */
+             count_instance++;
+
+           next:
+             ;
+           }
+
+         /* Return true if no instances remain inside
+            PREV->instances, so that the now purposeless desc may be
+            removed.  */
+         return !count_instance;
+       }
+
+      return true;
+    }
 
   if (NILP (prev->instances) || !family_equal_p)
     return false;
diff --git a/src/treesit.c b/src/treesit.c
index b48ad47991e..f8673f8e895 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -1900,6 +1900,10 @@ Return nil if NODE has no parent.  If NODE is nil, 
return nil.  */)
   TSNode treesit_node = XTS_NODE (node)->node;
   Lisp_Object parser = XTS_NODE (node)->parser;
   TSTreeCursor cursor;
+  /* See the comments to treesit_cursor_helper about the algorithm for
+     finding the parent node.  The complexity is roughly proportional
+     to the square root of the current node's depth in the parse tree,
+     and we punt if the tree is too deep.  */
   if (!treesit_cursor_helper (&cursor, treesit_node, parser))
     return return_value;
 
diff --git a/src/w32term.c b/src/w32term.c
index 57dc6b465e4..a5f17a18213 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -3412,7 +3412,7 @@ w32_construct_mouse_wheel (struct input_event *result, 
W32Msg *msg,
            ((double)FRAME_LINE_HEIGHT (f) * scroll_unit)
            / ((double)WHEEL_DELTA / delta);
       nlines = value_to_report / FRAME_LINE_HEIGHT (f) + 0.5;
-      result->arg = list3 (make_fixnum (nlines),
+      result->arg = list3 (make_fixnum (eabs (nlines)),
                           make_float (0.0),
                           make_float (value_to_report));
     }
diff --git a/test/lisp/cus-edit-tests.el b/test/lisp/cus-edit-tests.el
index 3a788f19745..9ceab16e194 100644
--- a/test/lisp/cus-edit-tests.el
+++ b/test/lisp/cus-edit-tests.el
@@ -128,7 +128,6 @@
   ;; Simulate changing the value.
   (let* ((choice (widget-at))
          (args (widget-get choice :args))
-         (const-opt (car (widget-get choice :children)))
          (list-opt (nth 1 args)))
     (widget-put choice :explicit-choice list-opt)
     (widget-value-set choice (widget-default-get list-opt)))
diff --git a/test/lisp/eshell/em-glob-tests.el 
b/test/lisp/eshell/em-glob-tests.el
index c33af88a374..6e07225657c 100644
--- a/test/lisp/eshell/em-glob-tests.el
+++ b/test/lisp/eshell/em-glob-tests.el
@@ -26,6 +26,13 @@
 (require 'ert)
 (require 'em-glob)
 
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
+(defvar eshell-prefer-lisp-functions)
+
 (defmacro with-fake-files (files &rest body)
   "Evaluate BODY forms, pretending that FILES exist on the filesystem.
 FILES is a list of file names that should be reported as
@@ -54,6 +61,60 @@ component ending in \"symlink\" is treated as a symbolic 
link."
 
 ;;; Tests:
 
+(ert-deftest em-glob-test/expand/splice-results ()
+  "Test that globs are spliced into the argument list when
+`eshell-glob-splice-results' is non-nil."
+  (let ((eshell-prefer-lisp-functions t)
+        (eshell-glob-splice-results t))
+    (with-fake-files '("a.el" "b.el" "c.txt")
+      ;; Ensure the default expansion splices the glob.
+      (eshell-command-result-equal "list *.el" '("a.el" "b.el"))
+      (eshell-command-result-equal "list *.txt" '("c.txt"))
+      (eshell-command-result-equal "list *.no" '("*.no")))))
+
+(ert-deftest em-glob-test/expand/no-splice-results ()
+  "Test that globs are treated as lists when
+`eshell-glob-splice-results' is nil."
+  (let ((eshell-prefer-lisp-functions t)
+        (eshell-glob-splice-results nil))
+    (with-fake-files '("a.el" "b.el" "c.txt")
+      ;; Ensure the default expansion splices the glob.
+      (eshell-command-result-equal "list *.el" '(("a.el" "b.el")))
+      (eshell-command-result-equal "list *.txt" '(("c.txt")))
+      ;; The no-matches case is special here: the glob is just the
+      ;; string, not the list of results.
+      (eshell-command-result-equal "list *.no" '("*.no")))))
+
+(ert-deftest em-glob-test/expand/explicitly-splice-results ()
+  "Test explicitly splicing globs works the same no matter the
+value of `eshell-glob-splice-results'."
+  (let ((eshell-prefer-lisp-functions t))
+    (dolist (eshell-glob-splice-results '(nil t))
+      (ert-info ((format "eshell-glob-splice-results: %s"
+                         eshell-glob-splice-results))
+        (with-fake-files '("a.el" "b.el" "c.txt")
+          (eshell-command-result-equal "list $@{listify *.el}"
+                                       '("a.el" "b.el"))
+          (eshell-command-result-equal "list $@{listify *.txt}"
+                                       '("c.txt"))
+          (eshell-command-result-equal "list $@{listify *.no}"
+                                       '("*.no")))))))
+
+(ert-deftest em-glob-test/expand/explicitly-listify-results ()
+  "Test explicitly listifying globs works the same no matter the
+value of `eshell-glob-splice-results'."
+  (let ((eshell-prefer-lisp-functions t))
+    (dolist (eshell-glob-splice-results '(nil t))
+      (ert-info ((format "eshell-glob-splice-results: %s"
+                         eshell-glob-splice-results))
+        (with-fake-files '("a.el" "b.el" "c.txt")
+          (eshell-command-result-equal "list ${listify *.el}"
+                                       '(("a.el" "b.el")))
+          (eshell-command-result-equal "list ${listify *.txt}"
+                                       '(("c.txt")))
+          (eshell-command-result-equal "list ${listify *.no}"
+                                       '(("*.no"))))))))
+
 (ert-deftest em-glob-test/match-any-string ()
   "Test that \"*\" pattern matches any string."
   (with-fake-files '("a.el" "b.el" "c.txt" "dir/a.el")
@@ -191,6 +252,9 @@ component ending in \"symlink\" is treated as a symbolic 
link."
   (with-fake-files '("foo.el" "bar.el")
     (should (equal (eshell-extended-glob "*.txt")
                    "*.txt"))
+    (let ((eshell-glob-splice-results t))
+      (should (equal (eshell-extended-glob "*.txt")
+                     '("*.txt"))))
     (let ((eshell-error-if-no-glob t))
       (should-error (eshell-extended-glob "*.txt")))))
 
diff --git a/test/lisp/eshell/em-hist-tests.el 
b/test/lisp/eshell/em-hist-tests.el
index 35ae6bdc239..0f143355115 100644
--- a/test/lisp/eshell/em-hist-tests.el
+++ b/test/lisp/eshell/em-hist-tests.el
@@ -22,8 +22,16 @@
 (require 'ert)
 (require 'ert-x)
 (require 'em-hist)
+(require 'eshell)
 
-(ert-deftest eshell-write-readonly-history ()
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
+;;; Tests:
+
+(ert-deftest em-hist-test/write-readonly-history ()
   "Test that having read-only strings in history is okay."
   (ert-with-temp-file histfile
     (let ((eshell-history-ring (make-ring 2)))
@@ -33,6 +41,39 @@
                    (propertize "echo bar" 'read-only t))
       (eshell-write-history histfile))))
 
+(ert-deftest em-hist-test/add-to-history/allow-dups ()
+  "Test adding to history, allowing dups."
+  (let ((eshell-hist-ignoredups nil))
+    (with-temp-eshell
+     (eshell-insert-command "echo hi")
+     (eshell-insert-command "echo bye")
+     (eshell-insert-command "echo bye")
+     (eshell-insert-command "echo hi")
+     (should (equal (ring-elements eshell-history-ring)
+                    '("echo hi" "echo bye" "echo bye" "echo hi"))))))
+
+(ert-deftest em-hist-test/add-to-history/no-consecutive-dups ()
+  "Test adding to history, ignoring consecutive dups."
+  (let ((eshell-hist-ignoredups t))
+    (with-temp-eshell
+     (eshell-insert-command "echo hi")
+     (eshell-insert-command "echo bye")
+     (eshell-insert-command "echo bye")
+     (eshell-insert-command "echo hi")
+     (should (equal (ring-elements eshell-history-ring)
+                    '("echo hi" "echo bye" "echo hi"))))))
+
+(ert-deftest em-hist-test/add-to-history/erase-dups ()
+  "Test adding to history, erasing any old dups."
+  (let ((eshell-hist-ignoredups 'erase))
+    (with-temp-eshell
+     (eshell-insert-command "echo hi")
+     (eshell-insert-command "echo bye")
+     (eshell-insert-command "echo bye")
+     (eshell-insert-command "echo hi")
+     (should (equal (ring-elements eshell-history-ring)
+                    '("echo hi" "echo bye"))))))
+
 (provide 'em-hist-test)
 
 ;;; em-hist-tests.el ends here
diff --git a/test/lisp/eshell/esh-io-tests.el b/test/lisp/eshell/esh-io-tests.el
index ed350a9691c..ce80f3a8f08 100644
--- a/test/lisp/eshell/esh-io-tests.el
+++ b/test/lisp/eshell/esh-io-tests.el
@@ -31,6 +31,9 @@
 
 (defvar eshell-test-value nil)
 
+(defvar eshell-test-value-with-fun nil)
+(defun eshell-test-value-with-fun ())
+
 (defun eshell-test-file-string (file)
   "Return the contents of FILE as a string."
   (with-temp-buffer
@@ -117,6 +120,13 @@
      (eshell-insert-command "echo new >> #'eshell-test-value"))
     (should (equal eshell-test-value "oldnew"))))
 
+(ert-deftest esh-io-test/redirect-symbol/with-function-slot ()
+  "Check that redirecting to a symbol with function slot set works."
+  (let ((eshell-test-value-with-fun))
+    (with-temp-eshell
+     (eshell-insert-command "echo hi > #'eshell-test-value-with-fun"))
+    (should (equal eshell-test-value-with-fun "hi"))))
+
 (ert-deftest esh-io-test/redirect-marker ()
   "Check that redirecting to a marker works."
   (with-temp-buffer
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 3e58fe749dd..ff646f5f977 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -766,6 +766,52 @@ it, since the setter is nil."
    (eshell-match-command-output "echo $INSIDE_EMACS[, 1]"
                                 "eshell")))
 
+(ert-deftest esh-var-test/pager-var/default ()
+  "Test that retrieving the default value of $PAGER works.
+This should be the value of `comint-pager' if non-nil, otherwise
+the value of the $PAGER env var."
+  (let ((comint-pager nil)
+        (process-environment (cons "PAGER=cat" process-environment)))
+    (eshell-command-result-equal "echo $PAGER" "cat")
+    (setq comint-pager "less")
+    (eshell-command-result-equal "echo $PAGER" "less")))
+
+(ert-deftest esh-var-test/pager-var/set ()
+  "Test that setting $PAGER in Eshell overrides the default value."
+  (let ((comint-pager nil)
+        (process-environment (cons "PAGER=cat" process-environment)))
+    (with-temp-eshell
+     (eshell-match-command-output "set PAGER bat" "bat")
+     (eshell-match-command-output "echo $PAGER" "bat"))
+    (setq comint-pager "less")
+    (with-temp-eshell
+     (eshell-match-command-output "set PAGER bat" "bat")
+     (eshell-match-command-output "echo $PAGER" "bat"))))
+
+(ert-deftest esh-var-test/pager-var/unset ()
+  "Test that unsetting $PAGER in Eshell overrides the default value."
+  (let ((comint-pager nil)
+        (process-environment (cons "PAGER=cat" process-environment)))
+    (with-temp-eshell
+     (eshell-insert-command "unset PAGER")
+     (eshell-match-command-output "echo $PAGER" "\\`\\'"))
+    (setq comint-pager "less")
+    (with-temp-eshell
+     (eshell-insert-command "unset PAGER")
+     (eshell-match-command-output "echo $PAGER" "\\`\\'"))))
+
+(ert-deftest esh-var-test/pager-var/set-locally ()
+  "Test setting $PAGER temporarily for a single command."
+  (let ((comint-pager nil)
+        (process-environment (cons "PAGER=cat" process-environment)))
+    (with-temp-eshell
+     (eshell-match-command-output "PAGER=bat env" "PAGER=bat\n")
+     (eshell-match-command-output "echo $PAGER" "cat"))
+    (setq comint-pager "less")
+    (with-temp-eshell
+     (eshell-match-command-output "PAGER=bat env" "PAGER=bat\n")
+     (eshell-match-command-output "echo $PAGER" "less"))))
+
 (ert-deftest esh-var-test/path-var/local-directory ()
   "Test using $PATH in a local directory."
   (let ((expected-path (string-join (eshell-get-path t) (path-separator))))



reply via email to

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