emacs-diffs
[Top][All Lists]
Advanced

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

scratch/pkg 2a71c003af8: Merge branch 'master' into scratch/pkg


From: Gerd Moellmann
Subject: scratch/pkg 2a71c003af8: Merge branch 'master' into scratch/pkg
Date: Mon, 4 Sep 2023 14:24:37 -0400 (EDT)

branch: scratch/pkg
commit 2a71c003af82e16f588bfc24094235d20bc1f597
Merge: ec637f1d0b8 f8d82b42818
Author: Gerd Moellmann <gerd.moellmann@gmail.com>
Commit: Gerd Moellmann <gerd.moellmann@gmail.com>

    Merge branch 'master' into scratch/pkg
---
 java/README => admin/notes/java              |   97 ++-
 doc/emacs/android.texi                       |   23 +-
 doc/emacs/haiku.texi                         |  112 +--
 doc/emacs/maintaining.texi                   |    7 +-
 doc/emacs/package.texi                       |    8 +-
 doc/lispref/commands.texi                    |   10 -
 doc/lispref/control.texi                     |   57 +-
 doc/lispref/edebug.texi                      |    2 +
 doc/lispref/positions.texi                   |   15 +-
 doc/lispref/sequences.texi                   |    3 +-
 doc/misc/eglot.texi                          |   10 +-
 doc/misc/eshell.texi                         |   27 +-
 doc/misc/mh-e.texi                           |    3 +-
 doc/misc/octave-mode.texi                    |    2 +-
 doc/misc/transient.texi                      |  119 +--
 doc/misc/url.texi                            |   34 -
 etc/EGLOT-NEWS                               |   10 +
 etc/NEWS                                     |   67 +-
 etc/emacsclient.desktop                      |    2 +-
 etc/refcards/orgcard.tex                     |    2 +-
 java/AndroidManifest.xml.in                  |   75 +-
 java/README                                  | 1027 +-------------------------
 java/org/gnu/emacs/EmacsNative.java          |    4 +
 java/org/gnu/emacs/EmacsOpenActivity.java    |    4 +
 java/org/gnu/emacs/EmacsService.java         |   19 +-
 java/org/gnu/emacs/EmacsView.java            |   20 +
 java/org/gnu/emacs/EmacsWindow.java          |    2 +-
 lisp/bindings.el                             |    2 +-
 lisp/button.el                               |    2 +-
 lisp/edmacro.el                              |    2 +-
 lisp/elec-pair.el                            |    2 +-
 lisp/emacs-lisp/checkdoc.el                  |   41 +-
 lisp/emacs-lisp/cl-macs.el                   |    3 +-
 lisp/emacs-lisp/comp.el                      |    3 +-
 lisp/emacs-lisp/disass.el                    |   17 +-
 lisp/emacs-lisp/edebug.el                    |   48 +-
 lisp/emacs-lisp/gv.el                        |    1 -
 lisp/emacs-lisp/package-vc.el                |  244 +++---
 lisp/emacs-lisp/package.el                   |    9 +-
 lisp/emacs-lisp/syntax.el                    |  288 ++++----
 lisp/eshell/em-basic.el                      |   32 +
 lisp/eshell/em-dirs.el                       |   15 +-
 lisp/eshell/em-glob.el                       |    4 +-
 lisp/eshell/em-pred.el                       |   24 +-
 lisp/eshell/em-prompt.el                     |   60 +-
 lisp/eshell/esh-arg.el                       |    9 +-
 lisp/eshell/esh-cmd.el                       |  105 +--
 lisp/eshell/esh-io.el                        |    2 +-
 lisp/eshell/esh-proc.el                      |   17 +-
 lisp/eshell/esh-util.el                      |   47 +-
 lisp/eshell/eshell.el                        |    4 +-
 lisp/filesets.el                             |   31 +-
 lisp/frame.el                                |    2 +-
 lisp/help-fns.el                             |    3 +-
 lisp/help.el                                 |   58 +-
 lisp/image-mode.el                           |    2 +-
 lisp/international/emoji.el                  |   35 +-
 lisp/jit-lock.el                             |    5 +-
 lisp/loadhist.el                             |    5 +-
 lisp/loadup.el                               |    2 +-
 lisp/minibuffer.el                           |   27 +-
 lisp/net/browse-url.el                       |    5 +-
 lisp/net/newst-backend.el                    |    9 -
 lisp/net/newst-plainview.el                  |   40 +-
 lisp/net/tramp-container.el                  |   55 +-
 lisp/net/tramp-sh.el                         |    3 +-
 lisp/net/tramp.el                            |  147 ++--
 lisp/obsolete/url-ns.el                      |    5 +-
 lisp/org/oc-basic.el                         |    2 +-
 lisp/org/org-element.el                      |   18 +-
 lisp/org/org-version.el                      |    4 +-
 lisp/org/org.el                              |   25 +-
 lisp/plstore.el                              |   39 +-
 lisp/progmodes/c-ts-mode.el                  |   55 +-
 lisp/progmodes/csharp-mode.el                |   10 +-
 lisp/progmodes/dockerfile-ts-mode.el         |    5 +-
 lisp/progmodes/ebnf2ps.el                    |    2 +-
 lisp/progmodes/eglot.el                      |  149 +++-
 lisp/progmodes/gdb-mi.el                     |   18 +-
 lisp/progmodes/gud.el                        |   22 +-
 lisp/progmodes/heex-ts-mode.el               |    5 +-
 lisp/progmodes/java-ts-mode.el               |   51 +-
 lisp/progmodes/js.el                         |   41 +-
 lisp/progmodes/json-ts-mode.el               |    4 +-
 lisp/progmodes/make-mode.el                  |  122 +--
 lisp/progmodes/prog-mode.el                  |    6 +-
 lisp/progmodes/project.el                    |    7 +-
 lisp/progmodes/ruby-ts-mode.el               |   77 +-
 lisp/progmodes/sh-script.el                  |    9 +-
 lisp/progmodes/typescript-ts-mode.el         |   40 +-
 lisp/progmodes/xref.el                       |   43 +-
 lisp/ps-print.el                             |   16 +-
 lisp/startup.el                              |    2 +-
 lisp/strokes.el                              |   25 +-
 lisp/subr.el                                 |   16 +
 lisp/tab-bar.el                              |   74 +-
 lisp/tab-line.el                             |    5 +-
 lisp/term/android-win.el                     |    2 +-
 lisp/textmodes/html-ts-mode.el               |   19 +-
 lisp/textmodes/reftex-vars.el                |    2 +-
 lisp/textmodes/reftex.el                     |   15 +-
 lisp/touch-screen.el                         |   31 +-
 lisp/treesit.el                              |  153 ++--
 lisp/url/url-gw.el                           |   17 +-
 lisp/url/url-vars.el                         |    2 +-
 lisp/vc/ediff-util.el                        |   35 +-
 lisp/vc/emerge.el                            |   30 +-
 lisp/vc/vc-git.el                            |   18 +-
 lisp/vc/vc-hg.el                             |    5 +-
 lisp/vc/vc-hooks.el                          |    9 +
 lisp/vc/vc.el                                |   21 +-
 lisp/wid-edit.el                             |   22 +-
 src/android.c                                |   68 +-
 src/android.h                                |    8 +-
 src/androidfns.c                             |   13 +
 src/androidvfs.c                             |   21 +-
 src/chartab.c                                |    3 +-
 src/data.c                                   |    2 -
 src/fileio.c                                 |    2 +-
 src/haiku_support.cc                         |    4 -
 src/sfnt.c                                   |   38 +-
 src/treesit.c                                |  106 +--
 test/lisp/cedet/semantic/bovine/gcc-tests.el |  109 +--
 test/lisp/epg-tests.el                       |   11 +-
 test/lisp/eshell/em-prompt-tests.el          |  109 ++-
 test/lisp/eshell/esh-util-tests.el           |   30 +
 test/lisp/eshell/eshell-tests-helpers.el     |   37 +-
 test/lisp/proced-tests.el                    |    3 +-
 test/lisp/vc/vc-tests.el                     |    5 +-
 129 files changed, 2411 insertions(+), 2607 deletions(-)

diff --git a/java/README b/admin/notes/java
similarity index 90%
copy from java/README
copy to admin/notes/java
index e518e9fbb2f..125ac0aad67 100644
--- a/java/README
+++ b/admin/notes/java
@@ -1,28 +1,8 @@
-This directory holds the Java sources of the port of GNU Emacs to
-Android-like systems, along with files needed to create an application
-package out of them.  If you need to build this port, please read the
-file INSTALL in this directory.
+Installation instructions for Android
+Copyright (C) 2023 Free Software Foundation, Inc.
+See the end of the file for license conditions.
 
-The ``org/gnu/emacs'' subdirectory contains the Java sources under the
-``org.gnu.emacs'' package identifier.
-
-``AndroidManifest.xml'' contains a manifest describing the Java
-sources to the system.
-
-The ``res'' directory contains resources, mainly the Emacs icon and
-several ``boolean resources'' which are used as a form of conditional
-evaluation for manifest entries.
-
-`emacs.keystore' is the signing key used to build Emacs.  It is kept
-here, and we encourage all people redistributing Emacs to use this
-key.  It holds no security value, and otherwise it will be impossible
-to install different builds of Emacs on top of each other.
-
-Please keep the Java code indented with tabs and formatted according
-to the rules for C code in the GNU coding standards.  Always use
-C-style comments.
-
-======================================================================
+
 
 OVERVIEW OF JAVA
 
@@ -1046,3 +1026,72 @@ public class Foo
 {
   Object bar;
 };
+
+
+
+COMPATIBILITY
+
+There are three variables set within every Android application that
+extert influence over the set of Android systems it supports, and the
+measures it must take to function faithfully on each of those systems:
+the minimum API level, compile SDK version and target API level.
+
+The minimum API level is the earliest version of Android that is
+permitted to install and run the application.  For Emacs, this is
+established by detecting the __ANDROID_API__ preprocessor macro
+defined within the Android C compiler.
+
+Before Java code executes any Android API calls that are not present
+within Android 2.2 (API level 8), the lowest API level supported by
+Emacs as a whole, it must first check the value of the:
+
+  Build.VERSION.SDK_INT
+
+variable, which is always set to the API level of the system Emacs is
+presently installed within.  For example, before calling
+`dispatchKeyEventFromInputMethod', a function absent from Android 6.0
+(API level 23) or earlier, check:
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
+      view.imManager.dispatchKeyEventFromInputMethod (view, key);
+    else
+      {
+
+where `N' is a constant defined to 24.
+
+The compile SDK version is the version of the Android SDK headers Java
+code is compiled against.  Because Java does not provide conditional
+compilation constructs, Emacs can't be compiled with any version of
+these headers other than the version mentioned in `java/INSTALL', but
+the headers used do not affect the set of supported systems provided
+that the version checks illustrated above are performed where
+necessary.
+
+The target API level is a number within java/AndroidManifest.xml.in
+the system refers to when deciding whether to enable
+backwards-incompatible modifications to the behavior of various system
+APIs.  For any given Android version, backwards incompatible changes
+in that version will be disabled for applications whose target API
+levels don't exceed its own.
+
+The target API should nevertheless be updated to match every major
+Android update, as Google has stated their intentions to prohibit
+users from installing applications targeting ``out-of-date'' versions
+of Android, though this threat has hitherto been made good on.
+
+
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index 5e7ff0e4bb3..d831a7a1884 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -129,8 +129,7 @@ buffer.
   Since there is no other way to start the @command{emacsclient}
 program (@pxref{Emacs Server}) from another Android program, Emacs
 provides a wrapper around the @command{emacsclient} program, which is
-registered with the system as an application that can open all text
-files.
+registered with the system as an application that can open any file.
 
   When that wrapper is selected as the program with which to open a
 file, it invokes @command{emacsclient} with the options
@@ -154,6 +153,11 @@ directory, or try to open files in it yourself.
 case such files are copied to a temporary directory before being
 opened.
 
+@cindex ``org-protocol'' links, android
+  In addition to opening ordinary text files, Emacs also registers its
+@command{emacsclient} wrapper as a program capable of opening
+``org-protocol'' links (@pxref{Protocols,,,org, The Org Manual}).
+
 @node Android File System
 @section What Files Emacs Can Access on Android
 @cindex /assets directory, android
@@ -293,7 +297,7 @@ provide, placing their files within the directory
 @file{/content/storage}.
 
 @findex android-request-directory-access
-  Before Emacs is granted access to any of these directories, it must
+  Before Emacs is granted access to one of these directories, it must
 first request the right to access it.  This is done by running the
 command (@pxref{M-x}) @code{android-request-directory-access}, which
 displays a file selection dialog.
@@ -663,6 +667,19 @@ in Emacs.
 modifier: it is referred to as @key{SYM} on Android keyboards and
 within the Settings keymap menu.
 
+@vindex android-intercept-control-space
+@cindex @kbd{C-SPC} interception, android
+  Android input methods have a penchant for irritating users by
+silently discarding key sequences containing @kbd{C-SPC} during the
+event filtering process, that they normally have no real application
+for such key sequences notwithstanding.  By default, Emacs intercepts
+these key sequences before they can be filtered by the input method.
+
+  If this proves unwanted (for instance, if the input method treats
+@kbd{C-SPC} as a shortcut key for switching languages), it can be
+disabled by setting the variable
+@code{android-intercept-control-space} to @code{nil}.
+
 @node Android Fonts
 @section Font Backends and Selection under Android
 @cindex fonts, android
diff --git a/doc/emacs/haiku.texi b/doc/emacs/haiku.texi
index 1506bc8f912..0bb216c14ae 100644
--- a/doc/emacs/haiku.texi
+++ b/doc/emacs/haiku.texi
@@ -8,52 +8,55 @@
   Haiku is a Unix-like operating system that originated as a
 re-implementation of the operating system BeOS.
 
-  This section describes the peculiarities of using Emacs built with
-the Application Kit, the windowing system native to Haiku.  The
-oddities described here do not apply to using Emacs on Haiku built
-without windowing support, or built with X11.
+  This appendix describes the peculiarities of using Emacs built with
+the Application Kit, the windowing system indigenous to Haiku.  The
+idiosyncracies illustrated here do not apply to Emacs on Haiku built
+without windowing support, or configured with X11.
 
 @menu
 * Haiku Basics::        Basic Emacs usage and installation under Haiku.
-* Haiku Fonts::         The various options for displaying fonts on Haiku.
+* Haiku Fonts::         Various options for displaying fonts on Haiku.
 @end menu
 
 @node Haiku Basics
-@section Installation and usage peculiarities under Haiku
+@section Haiku Installation and Startup
 @cindex haiku application
 @cindex haiku installation
 
-  Emacs installs two separate executables under Haiku; it is up to the
-user to decide which one suits him best: A regular executable, with
-the lowercase name @code{emacs}, and a binary containing
-Haiku-specific application metadata, with the name @code{Emacs}.
-
-@cindex launching Emacs from the tracker
-@cindex tty Emacs in haiku
-  If you are launching Emacs from the Tracker, or want to make the
-Tracker open files using Emacs, you should use the binary named
-@code{Emacs}; if you are going to use Emacs in the terminal, or wish
-to launch separate instances of Emacs, or do not care for the
-aforementioned system integration features, use the binary named
-@code{emacs} instead.
+  When Emacs is installed under Haiku, two executables are copied to
+the binaries directory, which are identical save for some identifying
+file-system metadata.  The first is a normal Emacs executable,
+@file{emacs}, whereas the second, @file{Emacs}, incorporates an icon
+and an application ``signature'' that abets the system in attributing
+both file types and open frames to it, thereby enabling it to receive
+file type assignments, and thus to open files directly from the
+Tracker.
+
+  Several file attributes are set within @file{Emacs} that prompt the
+system to permit only a single copy to run at any given time.  This
+invariant is verified upon the establishment of a display connection,
+and is enforced by terminating any Emacs process that attempts to
+create a display connection when one is already present.
+
+  For this and other reasons, @file{Emacs} is appropriate for starting
+a GUI session of Emacs, while @file{emacs} should be used for other
+types of Emacs sessions.
 
 @cindex modifier keys and system keymap (Haiku)
-@cindex haiku keymap
-  On Haiku, unusual modifier keys such as the Hyper key are
-unsupported.  By default, the super key corresponds with the option
-key defined by the operating system, the meta key with the command
-key, the control key with the system control key, and the shift key
-with the system shift key.  On a standard PC keyboard, Haiku should
-map these keys to positions familiar to those using a GNU system, but
-this may require some adjustment to your system's configuration to
-work.
-
-  It is impossible to type accented characters using the system super
-key map.
-
-  You can customize the correspondence between modifier keys known to
-the system, and those known to Emacs.  The variables that allow for
-that are described below.
+  Emacs is incapable of receiving unusual modifier keys such as
+@kbd{Hyper} under Haiku, or to receive accented characters produced
+from the system Super key map.
+
+  By default, the @key{Super} modifier is reported when the Option key
+defined by the operating system is depressed.  Analogously, the
+@key{Meta} modifier is assigned to the Command key, and of course
+@key{Control} to the system Control key and @key{Shift} to the system
+Shift key.  On a standard PC keyboard, Haiku should map these keys to
+positions familiar to those using a GNU system, but this may require
+some adjustment to your system's configuration to work.
+
+  You can customize the relation between modifier keys known to the
+system and those known to Emacs by means of the variables below.
 
 @cindex modifier key customization (Haiku)
 @table @code
@@ -86,25 +89,22 @@ instead.
 @cindex tooltips (haiku)
 @cindex haiku tooltips
   On Haiku, Emacs defaults to using the system tooltip mechanism.
-This usually leads to more responsive tooltips, but the tooltips will
-not be able to display text properties or faces.  If you need those
-features, customize the variable @code{use-system-tooltips} to the
-@code{nil} value, and Emacs will use its own implementation of
-tooltips.
+Tooltips thus generated are sometimes more responsive, but will not be
+able to display text properties or faces.  If you need those features,
+customize the variable @code{use-system-tooltips} to @code{nil} value,
+whereupon Emacs will use its own implementation of tooltips instead.
 
 @cindex X resources on Haiku
-  Unlike the X window system, Haiku does not have a system-wide
-resource database.  Since many important options are specified via
-X resources (@pxref{X Resources}), an emulation is provided: upon
+  Unlike the X window system, Haiku does not provide a system-wide
+resource database.  Since many important options are specified via X
+resources (@pxref{X Resources}), an emulation is provided: upon
 startup, Emacs will load a file named @file{GNU Emacs} inside the user
 configuration directory (normally @file{/boot/home/config/settings}),
 which should be a flattened system message where keys and values are
 both strings, and correspond to attributes and their values
-respectively.
-
-You can create such a file with the @command{xmlbmessage} tool.
+respectively.  Such a file may be created with the
+@command{xmlbmessage} tool.
 
-@subsection What to do when Emacs crashes
 @cindex crashes, Haiku
 @cindex haiku debugger
 @vindex haiku-debug-on-fatal-error
@@ -115,18 +115,18 @@ attach the report generated by the system debugger when 
reporting a
 bug.
 
 @node Haiku Fonts
-@section Font and font backend selection on Haiku
+@section Font Backends and Selection under Haiku
 @cindex font backend selection (Haiku)
 
-  Emacs, when built with Haiku windowing support, can be built with
-several different font backends.  You can specify font backends by
-specifying @kbd{-xrm Emacs.fontBackend:BACKEND} on the command line
-used to invoke Emacs, where @kbd{BACKEND} is one of the backends
-specified below, or on a per-frame basis by changing the
-@code{font-backend} frame parameter.
+  Emacs supports several different font backends when built with Haiku
+windowing support, though the subset supported is subject to the list
+of dependencies present and enabled when Emacs was configured.  You
+can specify which font backends to utilize by providing @w{@code{-xrm
+Emacs.fontBackend:@var{backend}}} on the command line used to invoke
+Emacs, where @var{backend} is one of the backends listed below, or on
+a per-frame basis by changing the @code{font-backend} frame parameter.
 
   Two of these backends, @code{ftcr} and @code{ftcrhb} are identical
 to their counterparts on the X Window System.  There is also a
 Haiku-specific backend named @code{haiku}, that uses the App Server to
-draw fonts, but does not at present support display of color font and
-emoji.
+draw fonts, but presently cannot display color fonts or Emoji.
diff --git a/doc/emacs/maintaining.texi b/doc/emacs/maintaining.texi
index 2dad70d3d13..2785ccb5109 100644
--- a/doc/emacs/maintaining.texi
+++ b/doc/emacs/maintaining.texi
@@ -447,9 +447,10 @@ merge-based version control system, a @samp{-} character 
indicates
 that the work file is unmodified, and @samp{:} indicates that it has
 been modified.  @samp{!} indicates that the file contains conflicts as
 result of a recent merge operation (@pxref{Merging}), or that the file
-was removed from the version control.  Finally, @samp{?} means that
-the file is under version control, but is missing from the working
-tree.
+was removed from the version control, or that it is versioned but also
+@dfn{ignored}, something that usually should not happen (@pxref{VC
+Ignore}).  Finally, @samp{?} means that the file is under version
+control, but is missing from the working tree.
 
   In a lock-based system, @samp{-} indicates an unlocked file, and
 @samp{:} a locked file; if the file is locked by another user (for
diff --git a/doc/emacs/package.texi b/doc/emacs/package.texi
index b294e3d58bd..96ebd35f547 100644
--- a/doc/emacs/package.texi
+++ b/doc/emacs/package.texi
@@ -690,13 +690,13 @@ an Org file.
 @item :make
 A string or list of strings providing the target or targets defined in
 the repository Makefile which should run before building the Info
-file.  Only takes effect when @code{package-vc-allow-side-effects} is
-non-nil.
+file.  Only takes effect when @code{package-vc-allow-build-commands}
+is non-nil.
 
 @item :shell-command
 A string providing the shell command to run before building the Info
-file.  Only takes effect when @code{package-vc-allow-side-effects} is
-non-@code{nil}.
+file.  Only takes effect when @code{package-vc-allow-build-commands}
+is non-@code{nil}.
 
 @item :vc-backend
 A symbol naming the VC backend to use for downloading a copy of the
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index 78fc43d0daf..a69879c30a9 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2762,16 +2762,6 @@ the @code{track-mouse} macro, that produces an event 
like this:
 (mouse-movement (#<frame *ielm* 0x102849a30> nil (563 . 205) 532301936))
 @end smallexample
 
-To handle a SIGUSR1 signal, define an interactive function, and
-bind it to the @code{signal usr1} event sequence:
-
-@smallexample
-(defun usr1-handler ()
-  (interactive)
-  (message "Got USR1 signal"))
-(keymap-global-set "<signal> <usr1>" 'usr1-handler)
-@end smallexample
-
 @node Classifying Events
 @subsection Classifying Events
 @cindex event type
diff --git a/doc/lispref/control.texi b/doc/lispref/control.texi
index 3aee9dd80e4..baa2a144bac 100644
--- a/doc/lispref/control.texi
+++ b/doc/lispref/control.texi
@@ -36,13 +36,14 @@ evaluated sequentially.  You can use macros to define your 
own control
 structure constructs (@pxref{Macros}).
 
 @menu
-* Sequencing::             Evaluation in textual order.
-* Conditionals::           @code{if}, @code{cond}, @code{when}, @code{unless}.
-* Combining Conditions::   @code{and}, @code{or}, @code{not}, and friends.
+* Sequencing::                  Evaluation in textual order.
+* Conditionals::                @code{if}, @code{cond}, @code{when}, 
@code{unless}.
+* Combining Conditions::        @code{and}, @code{or}, @code{not}, and friends.
 * Pattern-Matching Conditional::  How to use @code{pcase} and friends.
-* Iteration::              @code{while} loops.
-* Generators::             Generic sequences and coroutines.
-* Nonlocal Exits::         Jumping out of a sequence.
+* Iteration::                   @code{while} loops.
+* Generators::                  Generic sequences and coroutines.
+* Nonlocal Exits::              Jumping out of a sequence.
+* Conditional Compilation::     A facility like C's #if.
 @end menu
 
 @node Sequencing
@@ -2467,3 +2468,47 @@ quit, and the quit happens immediately after the function
 @code{ftp-setup-buffer} returns but before the variable @code{process} is
 set, the process will not be killed.  There is no easy way to fix this bug,
 but at least it is very unlikely.
+
+@node Conditional Compilation
+@section Conditional Compilation
+
+  There will be times when you want certain code to be compiled only
+when a certain condition holds.  This is particularly the case when
+maintaining Emacs packages; to keep the package compatible with older
+versions of Emacs you may need to use a function or variable which has
+become obsolete in the current version of Emacs.
+
+  You could just use a conditional form to select the old or new form
+at run time, but this tends to output annoying warning messages about
+the obsolete function/variable.  For such situations, the macro
+@code{static-if} comes in handy.  It is patterned after the special
+form @code{if} (@pxref{Conditionals}).
+
+  To use this facility for an older version of Emacs, copy the source
+for @code{static-if} from the Emacs source file @file{lisp/subr.el}
+into your package.
+
+@defmac static-if condition then-form else-forms...
+Test @var{condition} at macro-expansion time.  If its value is
+non-@code{nil}, expand the macro to @var{then-form}, otherwise expand
+it to @var{else-forms} enclosed in a @code{progn}.  @var{else-forms}
+may be empty.
+
+Here is an example of its use from CC Mode, which prevents a
+@code{defadvice} form being compiled in newer versions of Emacs:
+@example
+@group
+(static-if (boundp 'comment-line-break-function)
+    (progn)
+  (defvar c-inside-line-break-advice nil)
+  (defadvice indent-new-comment-line (around c-line-break-advice
+                                             activate preactivate)
+    "Call `c-indent-new-comment-line' if in CC Mode."
+    (if (or c-inside-line-break-advice
+            (not c-buffer-is-cc-mode))
+        ad-do-it
+      (let ((c-inside-line-break-advice t))
+        (c-indent-new-comment-line (ad-get-arg 0))))))
+@end group
+@end example
+@end defmac
diff --git a/doc/lispref/edebug.texi b/doc/lispref/edebug.texi
index c5be3a40d2c..7cf7ee51751 100644
--- a/doc/lispref/edebug.texi
+++ b/doc/lispref/edebug.texi
@@ -1289,6 +1289,8 @@ examples):
 @item sexp
 A single unevaluated Lisp object, which is not instrumented.
 @c an "expression" is not necessarily intended for evaluation.
+If the macro evaluates an argument at macro-expansion time, you should
+use @code{sexp} for it rather than @code{form}.
 
 @item form
 A single evaluated expression, which is instrumented.  If your macro
diff --git a/doc/lispref/positions.texi b/doc/lispref/positions.texi
index 98cf81be107..5ff89e992d9 100644
--- a/doc/lispref/positions.texi
+++ b/doc/lispref/positions.texi
@@ -872,36 +872,25 @@ defuns.  If the value is @code{nested}, navigation 
functions recognize
 nested defuns.
 @end defvar
 
-@defvar treesit-sentence-type-regexp
-The value of this variable is a regexp matching the node type of sentence
-nodes.  (For ``node'' and ``node type'', @pxref{Parsing Program Source}.)
-@end defvar
-
 @findex treesit-forward-sentence
 @findex forward-sentence
 @findex backward-sentence
 If Emacs is compiled with tree-sitter, it can use the tree-sitter
 parser information to move across syntax constructs.  Since what
 exactly is considered a sentence varies between languages, a major
-mode should set @code{treesit-sentence-type-regexp} to determine that.
+mode should set @code{treesit-thing-settings} to determine that.
 Then the mode can get navigation-by-sentence functionality for free,
 by using @code{forward-sentence} and
 @code{backward-sentence}(@pxref{Moving by Sentences,,, emacs, The
 extensible self-documenting text editor}).
 
-@defvar treesit-sexp-type-regexp
-The value of this variable is a regexp matching the node type of sexp
-nodes.  (For ``node'' and ``node type'', @pxref{Parsing Program
-Source}.)
-@end defvar
-
 @findex treesit-forward-sexp
 @findex forward-sexp@r{, and tree-sitter}
 @findex backward-sexp@r{, and tree-sitter}
 If Emacs is compiled with tree-sitter, it can use the tree-sitter
 parser information to move across syntax constructs.  Since what
 exactly is considered a sexp varies between languages, a major mode
-should set @code{treesit-sexp-type-regexp} to determine that.  Then
+should set @code{treesit-thing-settings} to determine that.  Then
 the mode can get navigation-by-sexp functionality for free, by using
 @code{forward-sexp} and @code{backward-sexp}(@pxref{Moving by
 Sentences,,, emacs, The extensible self-documenting text editor}).
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index dd5b723b479..c9c6bb31350 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -1645,7 +1645,8 @@ Refers to the element for character @var{char}
 
 @item @code{(@var{from} . @var{to})}
 A cons cell refers to all the characters in the inclusive range
-@samp{[@var{from}..@var{to}]}.
+@samp{[@var{from}..@var{to}]}.  In this case, the function returns the
+value for the character specified by @var{from}.
 @end table
 @end defun
 
diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index 6eb212ca841..3338756c63c 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -831,12 +831,14 @@ last buffer managed by it is killed.  @xref{Shutting Down 
LSP Servers}.
 The default is @code{nil}; if you want to shut down a server, use
 @kbd{M-x eglot-shutdown} (@pxref{Eglot Commands}).
 
-@item eglot-confirm-server-initiated-edits
+@item eglot-confirm-server-edits
 Various Eglot commands and code actions result in the language server
 sending editing commands to Emacs.  If this option's value is
-non-@code{nil} (the default), Eglot will ask for confirmation before
-performing edits initiated by the server or edits whose scope affects
-buffers other than the one where the user initiated the request.
+non-@code{nil}, Eglot will ask for confirmation before performing
+edits proposed by the language server.  This option's value can be
+crafted to require this confirmation for specific commands or only
+when the edit affects files not yet visited by the user.  Consult this
+option's docstring for more information.
 
 @item eglot-ignored-server-capabilities
 This variable's value is a list of language server capabilities that
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index f8f60bae13a..0ec90d0c159 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -234,6 +234,9 @@ the foreground.  That said, background processes invoked 
from Eshell
 can be controlled the same way as any other background process in
 Emacs.
 
+If a command exits abnormally, Eshell will display its exit code
+in the next prompt.
+
 @subsection Command form
 Command form looks much the same as in other shells.  A command
 consists of arguments separated by spaces; the first argument is the
@@ -334,7 +337,8 @@ As with other shells, you can escape special characters and 
spaces by
 prefixing the character with a backslash (@samp{\}), or by surrounding
 the string with apostrophes (@samp{''}) or double quotes (@samp{""}).
 This is needed especially for file names with special characters like
-pipe (@samp{|}), which could be part of remote file names.
+pipe (@samp{|}) or square brackets (@samp{[} or @samp{]}), which could
+be part of remote file names.
 
 When you escape a character with @samp{\} outside of any quotes, the
 result is the literal character immediately following it.  For
@@ -619,10 +623,23 @@ environment.
 @item eshell-debug
 @cmindex eshell-debug
 Toggle debugging information for Eshell itself.  You can pass this
-command the argument @code{errors} to enable/disable Eshell trapping
-errors when evaluating commands, or the argument @code{commands} to
-show/hide command execution progress in the buffer @code{*eshell last
-cmd*}.
+command one or more of the following arguments:
+
+@itemize @bullet
+
+@item
+@code{error}, to enable/disable Eshell trapping errors when
+evaluating commands;
+
+@item
+@code{form}, to show/hide Eshell command form manipulation in the
+buffer @code{*eshell last cmd*}; or
+
+@item
+@code{process}, to show/hide external process events in the buffer
+@code{*eshell last cmd*}.
+
+@end itemize
 
 @item exit
 @cmindex exit
diff --git a/doc/misc/mh-e.texi b/doc/misc/mh-e.texi
index caee0ed2c70..75788f18f03 100644
--- a/doc/misc/mh-e.texi
+++ b/doc/misc/mh-e.texi
@@ -1479,7 +1479,6 @@ Binding} of @samp{m}.
 
 @cindex @command{emacsclient}
 @cindex @command{xbuffy}
-@cindex @samp{gnuserv}
 @cindex Unix commands, @command{emacsclient}
 @cindex Unix commands, @command{xbuffy}
 
@@ -8920,7 +8919,7 @@ Bill Wohler, August 2008
 @c LocalWords: Baushke Bcc BBN Beranek bogofilter bogofilter's
 @c LocalWords: cmd CMU contrib cron
 @c LocalWords: DesBrisay Dcc devel dir dired docstring filll forw
-@c LocalWords: GECOS Gildea Gildea's Ginnean GnuCash goto gnuserv htm
+@c LocalWords: GECOS Gildea Gildea's Ginnean GnuCash goto htm
 @c LocalWords: ImageMagick inbox ispell keychain
 @c LocalWords: Larus licensor LocalWords lookup lpr
 @c LocalWords: makeinfo mairix mbox mh mhbuild mhl mhpath mlisp
diff --git a/doc/misc/octave-mode.texi b/doc/misc/octave-mode.texi
index 9f82af45203..0a599f64516 100644
--- a/doc/misc/octave-mode.texi
+++ b/doc/misc/octave-mode.texi
@@ -421,7 +421,7 @@ when Octave is waiting for input, or done sending output.
 
 @bye
 
-@c TODO Update
+@c TODO Update (and change gnuserv to emacsclient)
 
 @c @node Using the Emacs Info Reader for Octave
 @c @chapter Using the Emacs Info Reader for Octave
diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi
index e6144dcf2bc..e06f7759d1b 100644
--- a/doc/misc/transient.texi
+++ b/doc/misc/transient.texi
@@ -47,9 +47,9 @@ General Public License for more details.
 Taking inspiration from prefix keys and prefix arguments, Transient
 implements a similar abstraction involving a prefix command, infix
 arguments and suffix commands.  We could call this abstraction a
-“transient command”, but because it always involves at least two
+``transient command'', but because it always involves at least two
 commands (a prefix and a suffix) we prefer to call it just a
-“transient”.
+``transient''.
 
 When the user calls a transient prefix command, a transient
 (temporary) keymap is activated, which binds the transient's infix
@@ -153,9 +153,9 @@ Related Abstractions and Packages
 Taking inspiration from prefix keys and prefix arguments, Transient
 implements a similar abstraction involving a prefix command, infix
 arguments and suffix commands.  We could call this abstraction a
-“transient command”, but because it always involves at least two
+``transient command'', but because it always involves at least two
 commands (a prefix and a suffix) we prefer to call it just a
-“transient”.
+``transient''.
 
 @cindex transient prefix command
 @quotation
@@ -163,10 +163,10 @@ Transient keymaps are a feature provided by Emacs.  
Transients as
 implemented by this package involve the use of transient keymaps.
 
 Emacs provides a feature that it calls @dfn{prefix commands}.  When we
-talk about “prefix commands” in this manual, then we mean our own kind
-of “prefix commands”, unless specified otherwise.  To avoid ambiguity
+talk about ``prefix commands'' in this manual, then we mean our own kind
+of ``prefix commands'', unless specified otherwise.  To avoid ambiguity
 we sometimes use the terms @dfn{transient prefix command} for our kind and
-“regular prefix command” for Emacs' kind.
+``regular prefix command'' for Emacs' kind.
 
 @end quotation
 
@@ -217,7 +217,7 @@ looks a bit like this:
 
 @quotation
 This is a simplified version of @code{magit-tag}.  Info manuals do not
-support images or colored text, so the above “screenshot” lacks some
+support images or colored text, so the above ``screenshot'' lacks some
 information; in practice you would be able to tell whether the
 arguments @code{--force} and @code{--annotate} are enabled or not based on 
their
 color.
@@ -225,7 +225,7 @@ color.
 @end quotation
 
 @cindex command dispatchers
-Transient can be used to implement simple “command dispatchers”.  The
+Transient can be used to implement simple ``command dispatchers''.  The
 main benefit then is that the user can see all the available commands
 in a popup buffer.  That is useful by itself because it frees the user
 from having to remember all the keys that are valid after a certain
@@ -251,9 +251,9 @@ from Lisp.
 Invoking a transient suffix command with arguments is similar to
 invoking a command in a shell with command-line completion and history
 enabled.  One benefit of the Transient interface is that it remembers
-history not only on a global level (“this command was invoked using
+history not only on a global level (``this command was invoked using
 these arguments, and previously it was invoked using those other
-arguments”), but also remembers the values of individual arguments
+arguments''), but also remembers the values of individual arguments
 independently.  See @xref{Using History}.
 
 After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to
@@ -290,6 +290,18 @@ cannot be interrupted with prefix commands.)
 @node Usage
 @chapter Usage
 
+@menu
+* Invoking Transients::
+* Aborting and Resuming Transients::
+* Common Suffix Commands::
+* Saving Values::
+* Using History::
+* Getting Help for Suffix Commands::
+* Enabling and Disabling Suffixes::
+* Other Commands::
+* Configuration::
+@end menu
+
 @node Invoking Transients
 @section Invoking Transients
 
@@ -370,7 +382,7 @@ suspended transients, if any.
 Like @code{transient-quit-all}, this command quits an incomplete key
 sequence, if any, and all transients.  Additionally, it saves the
 stack of transients so that it can easily be resumed (which is
-particularly useful if you quickly need to do “something else” and
+particularly useful if you quickly need to do ``something else'' and
 the stack is deeper than a single transient, and/or you have already
 changed the values of some infix arguments).
 
@@ -397,7 +409,7 @@ as well as some other commands that are all bound to 
@kbd{C-x @var{KEY}}.  After
 @kbd{C-x} is pressed, a section featuring all these common commands is
 temporarily shown in the popup buffer.  After invoking one of them,
 the section disappears again.  Note, however, that one of these
-commands is described as “Show common permanently”; invoke that if you
+commands is described as ``Show common permanently''; invoke that if you
 want the common commands to always be shown for all transients.
 
 @table @asis
@@ -577,7 +589,7 @@ displayed at any level.
 
 The levels of individual transients and/or their individual suffixes
 can be changed interactively, by invoking the transient and then
-pressing @kbd{C-x l} to enter the “edit” mode, see below.
+pressing @kbd{C-x l} to enter the ``edit'' mode, see below.
 
 The default level for both transients and their suffixes is 4.  The
 @code{transient-default-level} option only controls the default for
@@ -927,8 +939,8 @@ The following functions share a few arguments:
 @item
 @var{SUFFIX} is a transient infix or suffix specification in the same form
 as expected by @code{transient-define-prefix}.  Note that an infix is a
-special kind of suffix.  Depending on context “suffixes” means
-“suffixes (including infixes)” or “non-infix suffixes”.  Here it
+special kind of suffix.  Depending on context ``suffixes'' means
+``suffixes (including infixes)'' or ``non-infix suffixes''.  Here it
 means the former.  @xref{Suffix Specifications}.
 
 @var{SUFFIX} may also be a group in the same form as expected by
@@ -1002,6 +1014,14 @@ signal an error.
 @node Defining New Commands
 @chapter Defining New Commands
 
+@menu
+* Defining Transients::
+* Binding Suffix and Infix Commands::
+* Defining Suffix and Infix Commands::
+* Using Infix Arguments::
+* Transient State::
+@end menu
+
 @node Defining Transients
 @section Defining Transients
 
@@ -1046,7 +1066,7 @@ however, call that function only when some condition is 
satisfied.
 All transients have a (possibly @code{nil}) value, which is exported when
 suffix commands are called, so that they can consume that value.
 For some transients it might be necessary to have a sort of
-secondary value, called a “scope”.  Such a scope would usually be
+secondary value, called a ``scope''.  Such a scope would usually be
 set in the command's @code{interactive} form and has to be passed to the
 setup function:
 
@@ -1068,8 +1088,8 @@ described below.
 
 Users and third-party packages can add additional bindings using
 functions such as @code{transient-insert-suffix} (@pxref{Modifying
-Existing Transients}).  These functions take a “suffix
-specification” as one of their arguments, which has the same form as
+Existing Transients}).  These functions take a ``suffix
+specification'' as one of their arguments, which has the same form as
 the specifications used in @code{transient-define-prefix}.
 
 @menu
@@ -1204,8 +1224,8 @@ The same form is also used when later binding additional 
commands
 using functions such as @code{transient-insert-suffix}, see @ref{Modifying 
Existing Transients}.
 
 Note that an infix is a special kind of suffix. Depending on context
-“suffixes” means “suffixes (including infixes)” or “non-infix
-suffixes”.  Here it means the former.
+``suffixes'' means ``suffixes (including infixes)'' or ``non-infix
+suffixes''.  Here it means the former.
 
 Suffix specifications have this form:
 
@@ -1299,8 +1319,8 @@ argument supported by the constructor of that class.  See 
@ref{Suffix Slots}.
 @cindex defining infix commands
 
 Note that an infix is a special kind of suffix. Depending on context
-“suffixes” means “suffixes (including infixes)” or “non-infix
-suffixes”.
+``suffixes'' means ``suffixes (including infixes)'' or ``non-infix
+suffixes''.
 
 @defmac transient-define-suffix name arglist [docstring] [keyword 
value]@dots{} body@dots{}
 This macro defines @var{NAME} as a transient suffix command.
@@ -1433,7 +1453,7 @@ returned value is a symbol, the transient prefix command.
 
 @cindex transient state
 
-Invoking a transient prefix command “activates” the respective
+Invoking a transient prefix command ``activates'' the respective
 transient, i.e., it puts a transient keymap into effect, which binds
 the transient's infix and suffix commands.
 
@@ -1445,20 +1465,20 @@ Invoking an infix command does not affect the transient 
state; the
 transient remains active.
 
 @item
-Invoking a (non-infix) suffix command “deactivates” the transient
+Invoking a (non-infix) suffix command ``deactivates'' the transient
 state by removing the transient keymap and performing some
 additional cleanup.
 
 @item
 Invoking a command that is bound in a keymap other than the
 transient keymap is disallowed and trying to do so results in a
-warning.  This does not “deactivate” the transient.
+warning.  This does not ``deactivate'' the transient.
 @end itemize
 
 But these are just the defaults.  Whether a certain command
-deactivates or “exits” the transient is configurable.  There is more
-than one way in which a command can be “transient” or “non-transient”;
-the exact behavior is implemented by calling a so-called “pre-command”
+deactivates or ``exits'' the transient is configurable.  There is more
+than one way in which a command can be ``transient'' or ``non-transient'';
+the exact behavior is implemented by calling a so-called ``pre-command''
 function.  Whether non-suffix commands are allowed to be called is
 configurable per transient.
 
@@ -1486,17 +1506,17 @@ essentially equivalent to it being @code{nil}.
 
 @item
 A suffix command can be a prefix command itself, i.e., a
-“sub-prefix”.  While a sub-prefix is active we nearly always want
-@kbd{C-g} to take the user back to the “super-prefix”.  However in rare
+``sub-prefix''.  While a sub-prefix is active we nearly always want
+@kbd{C-g} to take the user back to the ``super-prefix''.  However in rare
 cases this may not be desirable, and that makes the following
 complication necessary:
 
 For @code{transient-suffix} objects the @code{transient} slot is unbound.  We 
can
 ignore that for the most part because, as stated above, @code{nil} and the
-slot being unbound are equivalent, and mean “do exit”.  That isn't
+slot being unbound are equivalent, and mean ``do exit''.  That isn't
 actually true for suffixes that are sub-prefixes though.  For such
-suffixes unbound means “do exit but allow going back”, which is the
-default, while @code{nil} means “do exit permanently”, which requires that
+suffixes unbound means ``do exit but allow going back'', which is the
+default, while @code{nil} means ``do exit permanently'', which requires that
 slot to be explicitly set to that value.
 
 @item
@@ -1511,7 +1531,7 @@ called by @code{transient--pre-command}, a function on 
@code{pre-command-hook} a
 the value that they return determines whether the transient is exited.
 To do so the value of one of the constants @code{transient--exit} or
 @code{transient--stay} is used (that way we don't have to remember if @code{t} 
means
-“exit” or “stay”).
+``exit'' or ``stay'').
 
 Additionally, these functions may change the value of @code{this-command}
 (which explains why they have to be called using @code{pre-command-hook}),
@@ -1587,7 +1607,7 @@ i.e., for sub-prefixes.
 Suspend the active transient, saving the transient stack.
 
 This is used by the command @code{transient-suspend} and optionally also by
-“external events” such as @code{handle-switch-frame}.  Such bindings should
+``external events'' such as @code{handle-switch-frame}.  Such bindings should
 be added to @code{transient-predicate-map}.
 @end defun
 
@@ -1713,7 +1733,7 @@ The abstract @code{transient-child} class is the base 
class of both
 @code{transient-group} (and therefore all groups) as well as of
 @code{transient-suffix} (and therefore all suffix and infix commands).
 
-This class exists because the elements (or “children”) of certain
+This class exists because the elements (or ``children'') of certain
 groups can be other groups instead of suffix and infix commands.
 
 @item
@@ -1723,7 +1743,7 @@ group classes.
 @item
 The @code{transient-column} class is the simplest group.
 
-This is the default “flat” group.  If the class is not specified
+This is the default ``flat'' group.  If the class is not specified
 explicitly and the first element is not a vector (i.e., not a group),
 then this class is used.
 
@@ -1739,7 +1759,7 @@ Direct elements have to be groups whose elements have to 
be commands
 or strings.  Each subgroup represents a column.  This class takes
 care of inserting the subgroups' elements.
 
-This is the default “nested” group.  If the class is not specified
+This is the default ``nested'' group.  If the class is not specified
 explicitly and the first element is a vector (i.e., a group), then
 this class is used.
 
@@ -1917,7 +1937,7 @@ function is how the value of a transient is determined so 
that the
 invoked suffix command can use it.
 
 Currently most values are strings, but that is not set in stone.
-@code{nil} is not a value, it means “no value”.
+@code{nil} is not a value, it means ``no value''.
 
 Usually only infixes have a value, but see the method for
 @code{transient-suffix}.
@@ -2007,7 +2027,7 @@ multiple sub-lists.
 
 @item
 @code{scope} For some transients it might be necessary to have a sort of
-secondary value, called a “scope”.  See @code{transient-define-prefix}.
+secondary value, called a ``scope''.  See @code{transient-define-prefix}.
 @end itemize
 
 @anchor{Internal Prefix Slots}
@@ -2231,6 +2251,11 @@ available depending on user preference.
 @node Related Abstractions and Packages
 @chapter Related Abstractions and Packages
 
+@menu
+* Comparison With Prefix Keys and Prefix Arguments::
+* Comparison With Other Packages::
+@end menu
+
 @node Comparison With Prefix Keys and Prefix Arguments
 @section Comparison With Prefix Keys and Prefix Arguments
 
@@ -2478,9 +2503,9 @@ Both packages use transient keymaps to make a set of 
commands
 temporarily available and show the available commands in a popup
 buffer.
 
-A Hydra “body” is equivalent to a Transient “prefix” and a Hydra
-“head” is equivalent to a Transient “suffix”.  Hydra has no equivalent
-of a Transient “infix”.
+A Hydra ``body'' is equivalent to a Transient ``prefix'' and a Hydra
+``head'' is equivalent to a Transient ``suffix''.  Hydra has no equivalent
+of a Transient ``infix''.
 
 Both hydras and transients can be used as simple command dispatchers.
 Used like this they are similar to regular prefix commands and prefix
@@ -2589,14 +2614,14 @@ bindings.  The bindings that do use a prefix do so to 
avoid wasting
 too many non-prefix bindings, keeping them available for use in
 individual transients.  The bindings that do not use a prefix and that
 are @strong{not} grayed out are very important bindings that are 
@strong{always}
-available, even when invoking the “common command key prefix” or @strong{any
+available, even when invoking the ``common command key prefix'' or @strong{any
 other} transient-specific prefix.  The non-prefix keys that @strong{are} grayed
 out however, are not available when any incomplete prefix key sequence
-is active.  They do not use the “common command key prefix” because it
+is active.  They do not use the ``common command key prefix'' because it
 is likely that users want to invoke them several times in a row and
 e.g., @kbd{M-p M-p M-p} is much more convenient than @kbd{C-x M-p C-x M-p C-x 
M-p}.
 
-You may also have noticed that the “Set” command is bound to @kbd{C-x s},
+You may also have noticed that the ``Set'' command is bound to @kbd{C-x s},
 while Magit-Popup used to bind @kbd{C-c C-c} instead.  I have seen several
 users praise the latter binding (sic), so I did not change it
 willy-nilly.  The reason that I changed it is that using different
diff --git a/doc/misc/url.texi b/doc/misc/url.texi
index b5a6cb0e6a1..e6636e32507 100644
--- a/doc/misc/url.texi
+++ b/doc/misc/url.texi
@@ -1149,40 +1149,6 @@ If this variable is non-@code{nil} new network 
connections are never
 opened by the URL library.
 @end defvar
 
-@c @node Broken hostname resolution
-@c @subsection Broken Hostname Resolution
-
-@c @cindex hostname resolver
-@c @cindex resolver, hostname
-@c Some C libraries do not include the hostname resolver routines in
-@c their static libraries.  If Emacs was linked statically, and was not
-@c linked with the resolver libraries, it will not be able to get to any
-@c machines off the local network.  This is characterized by being able
-@c to reach someplace with a raw ip number, but not its hostname
-@c (@url{https://129.79.254.191/} works, but
-@c @url{https://www.cs.indiana.edu/} doesn't).  This used to happen on
-@c SunOS4 and Ultrix, but is now probably now rare.  If Emacs can't be
-@c rebuilt linked against the resolver library, it can use the external
-@c @command{nslookup} program instead.
-
-@c @defopt url-gateway-broken-resolution
-@c @cindex @code{nslookup} program
-@c @cindex program, @code{nslookup}
-@c If non-@code{nil}, this variable says to use the program specified by
-@c @code{url-gateway-nslookup-program} program to do hostname resolution.
-@c @end defopt
-
-@c @defopt url-gateway-nslookup-program
-@c The name of the program to do hostname lookup if Emacs can't do it
-@c directly.  This program should expect a single argument on the command
-@c line---the hostname to resolve---and should produce output similar to
-@c the standard Unix @command{nslookup} program:
-@c @example
-@c Name: www.cs.indiana.edu
-@c Address: 129.79.254.191
-@c @end example
-@c @end defopt
-
 @node History
 @section History
 
diff --git a/etc/EGLOT-NEWS b/etc/EGLOT-NEWS
index 01f0498eb81..ffc8095f752 100644
--- a/etc/EGLOT-NEWS
+++ b/etc/EGLOT-NEWS
@@ -20,6 +20,16 @@ https://github.com/joaotavora/eglot/issues/1234.
 
 * Changes in upcoming Eglot
 
+** Diff previews of edits and new variable 'eglot-confirm-server-edits'
+
+The variable 'eglot-confirm-server-edits' replaces the obsolete
+'eglot-confirm-server-initiated-edits' and brings about a new
+confirmation model, making it possible to have only certain commands
+require user confirmation.  The type of confirmation has also been
+enhanced.  In particular it allows a temporary 'diff-mode' buffer to
+display the proposed changes, so the user can apply them one by one.
+See bug#60338.
+
 ** Optimized file-watching capability
 
 Some servers, like the Pyright language server, issue too many file
diff --git a/etc/NEWS b/etc/NEWS
index 9d356240f9c..bbf4b67fe34 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -55,7 +55,7 @@ the signature) the automatically inferred function type as 
well.
 ---
 ** New user option 'describe-bindings-outline-rules'.
 This user option controls outline visibility in the output buffer of
-'describe-bindings' when 'describe-bindings-outline' in non-nil.
+'describe-bindings' when 'describe-bindings-outline' is non-nil.
 
 ** X selection requests are now handled much faster and asynchronously.
 This means it should be less necessary to disable the likes of
@@ -146,6 +146,12 @@ Anything following the symbol 
'mode-line-format-right-align' in
 right-aligned to is controlled by the new user option
 'mode-line-right-align-edge'.
 
+** Tab Bars and Tab Lines
+
+*** New user option 'tab-bar-tab-name-format-functions'.
+It can be used to add, remove and reorder functions that change
+the appearance of every tab on the tab bar.
+
 
 * Editing Changes in Emacs 30.1
 
@@ -349,6 +355,9 @@ this to your configuration:
 
     (keymap-set eshell-mode-map "<home>" #'eshell-bol-ignoring-prompt)
 
+This also means you no longer need to adjust 'eshell-prompt-regexp'
+when customizing your Eshell prompt.
+
 ---
 *** You can now properly unload Eshell.
 Calling '(unload-feature 'eshell)' no longer signals an error, and now
@@ -364,6 +373,9 @@ to load the edited aliases.
 Running 'rgrep' in Eshell now uses the Emacs grep facility instead of
 calling external rgrep.
 
++++
+*** If a command exits abnormally, the Eshell prompt now shows its exit code.
+
 ** Pcomplete
 
 ---
@@ -380,6 +392,13 @@ When this user option is non-nil, 'shell-get-old-input' 
('C-RET')
 includes multiple shell "\" continuation lines from command output.
 Default is nil.
 
+** Make mode
+
+*** The Makefile browser is now obsolete.
+The command 'makefile-switch-to-browser' command is now obsolete,
+together with related commands used in the "*Macros and Targets*"
+buffer.  We recommend using an alternative like 'imenu' instead.
+
 ** Prog Mode
 
 +++
@@ -532,9 +551,9 @@ project, that you can quickly select using 
'project-switch-project'
 ('C-x p p').
 
 ---
-*** New user option 'package-vc-allow-side-effects'.
-When non-nil, package specifications with side-effects for building
-software will be used when building a package.
+*** New user option 'package-vc-allow-build-commands'.
+Controls for which packages Emacs runs extra build commands when
+installing directly from the package VCS repository.
 
 ---
 *** New command to start an inferior Emacs loading only specific packages.
@@ -698,6 +717,23 @@ without specifying a file, like this:
 *** New user option 'image-dired-thumb-naming'.
 You can now configure how a thumbnail is named using this option.
 
+** checkdoc
+
+---
+*** New checkdock warning if not using lexical-binding.
+Checkdoc now warns if the first line of an Emacs Lisp file does not
+end with a "-*- lexical-binding: t -*-" cookie.  Customize the user
+option 'checkdoc-lexical-binding-flag' to nil to disable this warning.
+
+** url
+
++++
+*** 'url-gateway-broken-resolution' is now obsolete.
+This option was intended for use on SunOS 4.x and Ultrix systems,
+neither of which have been supported by Emacs since version 23.1.
+The user option 'url-gateway-nslookup-program' and the function
+'url-gateway-nslookup-host' are consequently also obsolete.
+
 
 * New Modes and Packages in Emacs 30.1
 
@@ -825,6 +861,12 @@ Use 'define-minor-mode' and 'define-globalized-minor-mode' 
instead.
 See the "(elisp) Porting Old Advice" node for help converting them
 to use 'advice-add' or 'define-advice' instead.
 
++++
+** New macro 'static-if' for conditional compilation of code.
+This macro hides a form from the compiler based on a compile-time
+condition.  This is handy for avoiding byte-compilation warnings about
+code that will never actually run under some conditions.
+
 +++
 ** Desktop notifications are now supported on the Haiku operating system.
 The new function 'haiku-notifications-notify' provides a subset of the
@@ -906,24 +948,17 @@ Major modes can now set this variable to customize the 
behavior of the
 The previous implementation of 'forward-sentence' is moved into its
 own function, to be bound by 'forward-sentence-function'.
 
-*** New buffer-local variable 'treesit-sentence-type-regexp'.
-Similarly to 'treesit-defun-type-regexp', this variable is used to
-define "sentences" in tree-sitter enabled modes.
-
 *** New function 'treesit-forward-sentence'.
-All tree-sitter enabled modes that define 'treesit-sentence-type-regexp'
-now set 'forward-sentence-function' to call 'treesit-forward-sentence'.
+All tree-sitter enabled modes that define 'sentence' in
+'treesit-thing-settings' now set 'forward-sentence-function' to call
+'treesit-forward-sentence'.
 
 ** Functions and variables to move by program sexps
 
-*** New buffer-local variable 'treesit-sexp-type-regexp'.
-Similarly to 'treesit-defun-type-regexp', this variable is used to
-define "sexps" in tree-sitter enabled modes.
-
 *** New function 'treesit-forward-sexp'.
 Tree-sitter conditionally sets 'forward-sexp-function' for major modes
-that have defined 'treesit-sexp-type-regexp' to enable sexp-related
-motion commands.
+that have defined 'sexp' in 'treesit-thing-settings' to enable
+sexp-related motion commands.
 
 ** New or changed byte-compilation warnings
 
diff --git a/etc/emacsclient.desktop b/etc/emacsclient.desktop
index a9f840c7033..4395d3b02bc 100644
--- a/etc/emacsclient.desktop
+++ b/etc/emacsclient.desktop
@@ -2,7 +2,7 @@
 Name=Emacs (Client)
 GenericName=Text Editor
 Comment=Edit text
-MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;x-scheme-handler/org-protocol;
 Exec=sh -c "if [ -n \\"\\$*\\" ]; then exec emacsclient --alternate-editor= 
--display=\\"\\$DISPLAY\\" \\"\\$@\\"; else exec emacsclient 
--alternate-editor= --create-frame; fi" sh %F
 Icon=emacs
 Type=Application
diff --git a/etc/refcards/orgcard.tex b/etc/refcards/orgcard.tex
index dd8cae5ce5e..23a2f73dba7 100644
--- a/etc/refcards/orgcard.tex
+++ b/etc/refcards/orgcard.tex
@@ -1,5 +1,5 @@
 % Reference Card for Org Mode
-\def\orgversionnumber{9.6.7}
+\def\orgversionnumber{9.6.8}
 \def\versionyear{2023}          % latest update
 \input emacsver.tex
 
diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in
index 2cbcdbc3e5b..21bb2af2530 100644
--- a/java/AndroidManifest.xml.in
+++ b/java/AndroidManifest.xml.in
@@ -107,73 +107,18 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>. -->
         <action android:name="android.intent.action.VIEW"/>
        <action android:name="android.intent.action.EDIT"/>
        <action android:name="android.intent.action.PICK"/>
-
         <category android:name="android.intent.category.DEFAULT"/>
+       <data android:mimeType="*/*"/>
+      </intent-filter>
+
+      <!-- Facilitate opening org-protocol:// URLs as well, the same
+           way emacsclient.desktop does.  -->
 
-       <data android:mimeType="image/aces"/>
-       <data android:mimeType="image/avci"/>
-       <data android:mimeType="image/avcs"/>
-       <data android:mimeType="image/avif"/>
-       <data android:mimeType="image/bmp"/>
-       <data android:mimeType="image/cgm"/>
-       <data android:mimeType="image/dicom-rle"/>
-       <data android:mimeType="image/dpx"/>
-       <data android:mimeType="image/emf"/>
-       <data android:mimeType="image/example"/>
-       <data android:mimeType="image/fits"/>
-       <data android:mimeType="image/g3fax"/>
-       <data android:mimeType="image/heic"/>
-       <data android:mimeType="image/heic-sequence"/>
-       <data android:mimeType="image/heif"/>
-       <data android:mimeType="image/heif-sequence"/>
-       <data android:mimeType="image/hej2k"/>
-       <data android:mimeType="image/hsj2"/>
-       <data android:mimeType="image/jls"/>
-       <data android:mimeType="image/jp2"/>
-       <data android:mimeType="image/jph"/>
-       <data android:mimeType="image/jphc"/>
-       <data android:mimeType="image/jpm"/>
-       <data android:mimeType="image/jpx"/>
-       <data android:mimeType="image/jxr"/>
-       <data android:mimeType="image/jxrA"/>
-       <data android:mimeType="image/jxrS"/>
-       <data android:mimeType="image/jxs"/>
-       <data android:mimeType="image/jxsc"/>
-       <data android:mimeType="image/jxsi"/>
-       <data android:mimeType="image/jxss"/>
-       <data android:mimeType="image/ktx"/>
-       <data android:mimeType="image/ktx2"/>
-       <data android:mimeType="image/naplps"/>
-       <data android:mimeType="image/png"/>
-       <data android:mimeType="image/prs.btif"/>
-       <data android:mimeType="image/prs.pti"/>
-       <data android:mimeType="image/pwg-raster"/>
-       <data android:mimeType="image/svg+xml"/>
-       <data android:mimeType="image/t38"/>
-       <data android:mimeType="image/tiff"/>
-       <data android:mimeType="image/tiff-fx"/>
-       <data android:mimeType="image/xpm"/>
-       <data android:mimeType="text/*"/>
-        <data android:mimeType="application/*xml"/>
-        <data android:mimeType="application/atom+xml"/>
-        <data android:mimeType="application/dxf"/>
-        <data android:mimeType="application/ecmascript"/>
-        <data android:mimeType="application/javascript"/>
-        <data android:mimeType="application/json"/>
-        <data android:mimeType="application/*log*"/>
-        <data android:mimeType="application/octet-stream"/>
-        <data android:mimeType="application/soap+xm"/>
-        <data android:mimeType="application/x-caramel"/>
-        <data android:mimeType="application/x-klaunch"/>
-        <data android:mimeType="application/x-latex"/>
-        <data android:mimeType="application/x-sh"/>
-        <data android:mimeType="application/x-tcl"/>
-        <data android:mimeType="application/x-tex*"/>
-        <data android:mimeType="application/x-troff*"/>
-        <data android:mimeType="application/xhtml+xml"/>
-        <data android:mimeType="application/xml*"/>
-        <data android:mimeType="application/zip"/>
-        <data android:mimeType="application/x-zip-compressed"/>
+      <intent-filter>
+        <action android:name="android.intent.action.VIEW"/>
+        <category android:name="android.intent.category.DEFAULT"/>
+        <category android:name="android.intent.category.BROWSABLE"/>
+        <data android:scheme="org-protocol"/>
       </intent-filter>
     </activity>
 
diff --git a/java/README b/java/README
index e518e9fbb2f..a909cdd22ef 100644
--- a/java/README
+++ b/java/README
@@ -22,1027 +22,6 @@ Please keep the Java code indented with tabs and formatted 
according
 to the rules for C code in the GNU coding standards.  Always use
 C-style comments.
 
-======================================================================
-
-OVERVIEW OF JAVA
-
-Emacs developers do not know Java, and there is no reason they should
-have to.  Thus, the code in this directory is confined to what is
-strictly necessary to support Emacs, and only uses a subset of Java
-written in a way that is easily understandable to C programmers.
-
-Java is required because the entire Android runtime is based around
-Java, and there is no way to write an Android program which runs
-without Java.
-
-This text exists to prime other Emacs developers, already familar with
-C, on the basic architecture of the Android port, and to teach them
-how to read and write the Java code found in this directory.
-
-Java is an object oriented language with automatic memory management
-compiled down to bytecode, which is then subject to interpretation by
-a Java virtual machine.
-
-What that means, is that:
-
-struct emacs_window
-{
-  int some_fields;
-  int of_emacs_window;
-};
-
-static void
-do_something_with_emacs_window (struct emacs_window *a, int n)
-{
-  a->some_fields = a->of_emacs_window + n;
-}
-
-would be written:
-
-public class EmacsWindow
-{
-  public int someFields;
-  public int ofEmacsWindow;
-
-  public void
-  doSomething (int n)
-  {
-    someFields = ofEmacsWindow + n;
-  }
-}
-
-and instead of doing:
-
-do_something_with_emacs_window (my_window, 1);
-
-you say:
-
-myWindow.doSomething (1);
-
-In addition to functions associated with an object of a given class
-(such as EmacsWindow), Java also has two other kinds of functions.
-
-The first are so-called ``static'' functions (the static means
-something entirely different from what it does in C.)
-
-A static function, while still having to be defined within a class,
-can be called without any object.  Instead of the object, you write
-the name of the Java class within which it is defined. For example,
-the following C code:
-
-int
-multiply_a_with_b_and_then_add_c (int a, int b, int c)
-{
-  return a * b + c;
-}
-
-would be:
-
-public class EmacsSomething
-{
-  public static int
-  multiplyAWithBAndThenAddC (int a, int b, int c)
-  {
-    return a * b + c;
-  }
-};
-
-Then, instead of calling:
-
-int foo;
-
-foo = multiply_a_with_b_then_add_c (1, 2, 3);
-
-you say:
-
-int foo;
-
-foo = EmacsSomething.multiplyAWithBAndThenAddC (1, 2, 3);
-
-In Java, ``static'' does not mean that the function is only used
-within its compilation unit!  Instead, the ``private'' qualifier is
-used to mean more or less the same thing:
-
-static void
-this_procedure_is_only_used_within_this_file (void)
-{
-  do_something ();
-}
-
-becomes
-
-public class EmacsSomething
-{
-  private static void
-  thisProcedureIsOnlyUsedWithinThisClass ()
-  {
-
-  }
-}
-
-the other kind are called ``constructors''.  They are functions that
-must be called to allocate memory to hold a class:
-
-public class EmacsFoo
-{
-  int bar;
-
-  public
-  EmacsFoo (int tokenA, int tokenB)
-  {
-    bar = tokenA + tokenB;
-  }
-}
-
-now, the following statement:
-
-EmacsFoo foo;
-
-foo = new EmacsFoo (1, 2);
-
-becomes more or less equivalent to the following C code:
-
-struct emacs_foo
-{
-  int bar;
-};
-
-struct emacs_foo *
-make_emacs_foo (int token_a, int token_b)
-{
-  struct emacs_foo *foo;
-
-  foo = xmalloc (sizeof *foo);
-  foo->bar = token_a + token_b;
-
-  return foo;
-}
-
-/* ... */
-
-struct emacs_foo *foo;
-
-foo = make_emacs_foo (1, 2);
-
-A class may have any number of constructors, or no constructors at
-all, in which case the compiler inserts an empty constructor.
-
-
-
-Sometimes, you will see Java code that looks like this:
-
-    allFiles = filesDirectory.listFiles (new FileFilter () {
-       @Override
-       public boolean
-       accept (File file)
-       {
-         return (!file.isDirectory ()
-                 && file.getName ().endsWith (".pdmp"));
-       }
-      });
-
-This is Java's version of GCC's nested function extension.  The major
-difference is that the nested function may still be called even after
-it goes out of scope, and always retains a reference to the class and
-local variables around where it was called.
-
-Being an object-oriented language, Java also allows defining that a
-class ``extends'' another class.  The following C code:
-
-struct a
-{
-  long thirty_two;
-};
-
-struct b
-{
-  struct a a;
-  long long sixty_four;
-};
-
-extern void do_something (struct a *);
-
-void
-my_function (struct b *b)
-{
-  do_something (&b->a);
-}
-
-is roughly equivalent to the following Java code, split into two
-files:
-
-  A.java
-
-public class A
-{
-  int thirtyTwo;
-
-  public void
-  doSomething ()
-  {
-    etcEtcEtc ();
-  }
-};
-
-  B.java
-
-public class B extends A
-{
-  long sixty_four;
-
-  public static void
-  myFunction (B b)
-  {
-    b.doSomething ();
-  }
-}
-
-the Java runtime has transformed the call to ``b.doSomething'' to
-``((A) b).doSomething''.
-
-However, Java also allows overriding this behavior, by specifying the
-@Override keyword:
-
-public class B extends A
-{
-  long sixty_four;
-
-  @Override
-  public void
-  doSomething ()
-  {
-    Something.doSomethingTwo ();
-    super.doSomething ();
-  }
-}
-
-now, any call to ``doSomething'' on a ``B'' created using ``new B ()''
-will end up calling ``Something.doSomethingTwo'', before calling back
-to ``A.doSomething''.  This override also applies in reverse; that is
-to say, even if you write:
-
-  ((A) b).doSomething ();
-
-B's version of doSomething will still be called, if ``b'' was created
-using ``new B ()''.
-
-This mechanism is used extensively throughout the Java language and
-Android windowing APIs.
-
-Elsewhere, you will encounter Java code that defines arrays:
-
-public class EmacsFrobinicator
-{
-  public static void
-  emacsFrobinicate (int something)
-  {
-    int[] primesFromSomething;
-
-    primesFromSomething = new int[numberOfPrimes];
-    /* ... */
-  }
-}
-
-Java arrays are similar to C arrays in that they can not grow.  But
-they are very much unlike C arrays in that they are always references
-(as opposed to decaying into pointers in only some situations), and
-contain information about their length.
-
-If another function named ``frobinicate1'' takes an array as an
-argument, then it need not take the length of the array.
-
-Instead, it may simply iterate over the array like so:
-
-int i, k;
-
-for (i = 0; i < array.length; ++i)
-  {
-    k = array[i];
-
-    Whatever.doSomethingWithK (k);
-  }
-
-The syntax used to define arrays is also slightly different.  As
-arrays are always references, there is no way for you to tell the
-runtime to allocate an array of size N in a structure (class.)
-
-Instead, if you need an array of that size, you must declare a field
-with the type of the array, and allocate the array inside the class's
-constructor, like so:
-
-public class EmacsArrayContainer
-{
-  public int[] myArray;
-
-  public
-  EmacsArrayContainer ()
-  {
-    myArray = new array[10];
-  }
-}
-
-while in C, you could just have written:
-
-struct emacs_array_container
-{
-  int my_array[10];
-};
-
-or, possibly even better,
-
-typedef int emacs_array_container[10];
-
-Alas, Java has no equivalent of `typedef'.
-
-Like in C, Java string literals are delimited by double quotes.
-Unlike C, however, strings are not NULL-terminated arrays of
-characters, but a distinct type named ``String''.  They store their
-own length, characters in Java's 16-bit ``char'' type, and are capable
-of holding NULL bytes.
-
-Instead of writing:
-
-wchar_t character;
-extern char *s;
-size_t s;
-
-  for (/* determine n, s in a loop.  */)
-    s += mbstowc (&character, s, n);
-
-or:
-
-const char *byte;
-
-for (byte = my_string; *byte; ++byte)
-  /* do something with *byte.  */;
-
-or perhaps even:
-
-size_t length, i;
-char foo;
-
-length = strlen (my_string);
-
-for (i = 0; i < length; ++i)
-  foo = my_string[i];
-
-you write:
-
-char foo;
-int i;
-
-for (i = 0; i < myString.length (); ++i)
-  foo = myString.charAt (0);
-
-Java also has stricter rules on what can be used as a truth value in a
-conditional.  While in C, any non-zero value is true, Java requires
-that every truth value be of the boolean type ``boolean''.
-
-What this means is that instead of simply writing:
-
-  if (foo || bar)
-
-where foo can either be 1 or 0, and bar can either be NULL or a
-pointer to something, you must explicitly write:
-
-  if (foo != 0 || bar != null)
-
-in Java.
-
-JAVA NATIVE INTERFACE
-
-Java also provides an interface for C code to interface with Java.
-
-C functions exported from a shared library become static Java
-functions within a class, like so:
-
-public class EmacsNative
-{
-  /* Obtain the fingerprint of this build of Emacs.  The fingerprint
-     can be used to determine the dump file name.  */
-  public static native String getFingerprint ();
-
-  /* Set certain parameters before initializing Emacs.
-
-     assetManager must be the asset manager associated with the
-     context that is loading Emacs.  It is saved and remains for the
-     remainder the lifetime of the Emacs process.
-
-     filesDir must be the package's data storage location for the
-     current Android user.
-
-     libDir must be the package's data storage location for native
-     libraries.         It is used as PATH.
-
-     cacheDir must be the package's cache directory.  It is used as
-     the `temporary-file-directory'.
-
-     pixelDensityX and pixelDensityY are the DPI values that will be
-     used by Emacs.
-
-     classPath must be the classpath of this app_process process, or
-     NULL.
-
-     emacsService must be the EmacsService singleton, or NULL. */
-  public static native void setEmacsParams (AssetManager assetManager,
-                                           String filesDir,
-                                           String libDir,
-                                           String cacheDir,
-                                           float pixelDensityX,
-                                           float pixelDensityY,
-                                           String classPath,
-                                           EmacsService emacsService);
-}
-
-Where the corresponding C functions are located in android.c, and
-loaded by the special invocation:
-
-  static
-  {
-    System.loadLibrary ("emacs");
-  };
-
-where ``static'' defines a section of code which will be run upon the
-object (containing class) being loaded.  This is like:
-
-  __attribute__((constructor))
-
-on systems where shared object constructors are supported.
-
-See http://docs.oracle.com/en/java/javase/19/docs/specs/jni/intro.html
-for more details.
-
-
-
-OVERVIEW OF ANDROID
-
-When the Android system starts an application, it does not actually
-call the application's ``main'' function.  It may not even start the
-application's process if one is already running.
-
-Instead, Android is organized around components.  When the user opens
-the ``Emacs'' icon, the Android system looks up and starts the
-component associated with the ``Emacs'' icon.  In this case, the
-component is called an activity, and is declared in
-the AndroidManifest.xml in this directory:
-
-    <activity android:name="org.gnu.emacs.EmacsActivity"
-             android:launchMode="singleTop"
-             android:windowSoftInputMode="adjustResize"
-             android:exported="true"
-             
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
-      <intent-filter>
-       <action android:name="android.intent.action.MAIN" />
-       <category android:name="android.intent.category.DEFAULT" />
-       <category android:name="android.intent.category.LAUNCHER" />
-      </intent-filter>
-    </activity>
-
-This tells Android to start the activity defined in ``EmacsActivity''
-(defined in org/gnu/emacs/EmacsActivity.java), a class extending the
-Android class ``Activity''.
-
-To do so, the Android system creates an instance of ``EmacsActivity''
-and the window system window associated with it, and eventually calls:
-
-  Activity activity;
-
-  activity.onCreate (...);
-
-But which ``onCreate'' is really called?
-It is actually the ``onCreate'' defined in EmacsActivity.java, as
-it overrides the ``onCreate'' defined in Android's own Activity class:
-
-  @Override
-  public void
-  onCreate (Bundle savedInstanceState)
-  {
-    FrameLayout.LayoutParams params;
-    Intent intent;
-
-Then, this is what happens step-by-step within the ``onCreate''
-function:
-
-    /* See if Emacs should be started with -Q. */
-    intent = getIntent ();
-    EmacsService.needDashQ
-      = intent.getBooleanExtra ("org.gnu.emacs.START_DASH_Q",
-                               false);
-
-Here, Emacs obtains the intent (a request to start a component) which
-was used to start Emacs, and sets a special flag if it contains a
-request for Emacs to start with the ``-Q'' command-line argument.
-
-    /* Set the theme to one without a title bar.  */
-
-    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
-      setTheme (android.R.style.Theme_DeviceDefault_NoActionBar);
-    else
-      setTheme (android.R.style.Theme_NoTitleBar);
-
-Next, Emacs sets an appropriate theme for the activity's associated
-window decorations.
-
-    params = new FrameLayout.LayoutParams (LayoutParams.MATCH_PARENT,
-                                          LayoutParams.MATCH_PARENT);
-
-    /* Make the frame layout.  */
-    layout = new FrameLayout (this);
-    layout.setLayoutParams (params);
-
-    /* Set it as the content view.  */
-    setContentView (layout);
-
-Then, Emacs creates a ``FrameLayout'', a widget that holds a single
-other widget, and makes it the activity's ``content view''.
-
-The activity itself is a ``FrameLayout'', so the ``layout parameters''
-here apply to the FrameLayout itself, and not its children.
-
-    /* Maybe start the Emacs service if necessary.  */
-    EmacsService.startEmacsService (this);
-
-And after that, Emacs calls the static function ``startEmacsService'',
-defined in the class ``EmacsService''. This starts the Emacs service
-component if necessary.
-
-    /* Add this activity to the list of available activities.  */
-    EmacsWindowAttachmentManager.MANAGER.registerWindowConsumer (this);
-
-    super.onCreate (savedInstanceState);
-
-Finally, Emacs registers that this activity is now ready to receive
-top-level frames (windows) created from Lisp.
-
-Activities come and go, but Emacs has to stay running in the mean
-time.  Thus, Emacs also defines a ``service'', which is a long-running
-component that the Android system allows to run in the background.
-
-Let us go back and review the definition of ``startEmacsService'':
-
-  public static void
-  startEmacsService (Context context)
-  {
-    if (EmacsService.SERVICE == null)
-      {
-       if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O)
-         /* Start the Emacs service now.  */
-         context.startService (new Intent (context,
-                                           EmacsService.class));
-       else
-         /* Display the permanant notification and start Emacs as a
-            foreground service.  */
-         context.startForegroundService (new Intent (context,
-                                                     EmacsService.class));
-      }
-  }
-
-If ``EmacsService.SERVICE'' does not yet exist, what this does is to
-tell the ``context'' (the equivalent of an Xlib Display *) to start a
-service defined by the class ``EmacsService''. Eventually, this
-results in ``EmacsService.onCreate'' being called:
-
-  @Override
-  public void
-  onCreate ()
-  {
-    AssetManager manager;
-    Context app_context;
-    String filesDir, libDir, cacheDir, classPath;
-    double pixelDensityX;
-    double pixelDensityY;
-
-Here is what this function does, step-by-step:
-
-    SERVICE = this;
-
-First, it sets the special static variable ``SERVICE'' to ``this'',
-which is a pointer to the ``EmacsService' object that was created.
-
-    handler = new Handler (Looper.getMainLooper ());
-
-Next, it creates a ``Handler'' object for the ``main looper''.
-This is a helper structure which allows executing code on the Android
-user interface thread.
-
-    manager = getAssets ();
-    app_context = getApplicationContext ();
-    metrics = getResources ().getDisplayMetrics ();
-    pixelDensityX = metrics.xdpi;
-    pixelDensityY = metrics.ydpi;
-
-Finally, it obtains:
-
-  - the asset manager, which is used to retrieve assets packaged
-    into the Emacs application package.
-
-  - the application context, used to obtain application specific
-    information.
-
-  - the display metrics, and from them, the X and Y densities in dots
-    per inch.
-
-Then, inside a ``try'' block:
-
-    try
-      {
-       /* Configure Emacs with the asset manager and other necessary
-          parameters.  */
-       filesDir = app_context.getFilesDir ().getCanonicalPath ();
-       libDir = getLibraryDirectory ();
-       cacheDir = app_context.getCacheDir ().getCanonicalPath ();
-
-It obtains the names of the Emacs home, shared library, and temporary
-file directories.
-
-       /* Now provide this application's apk file, so a recursive
-          invocation of app_process (through android-emacs) can
-          find EmacsNoninteractive.  */
-       classPath = getApkFile ();
-
-The name of the Emacs application package.
-
-       Log.d (TAG, "Initializing Emacs, where filesDir = " + filesDir
-              + ", libDir = " + libDir + ", and classPath = " + classPath);
-
-Prints a debug message to the Android system log with this
-information.
-
-       EmacsNative.setEmacsParams (manager, filesDir, libDir,
-                                   cacheDir, (float) pixelDensityX,
-                                   (float) pixelDensityY,
-                                   classPath, this);
-
-And calls the native function ``setEmacsParams'' (defined in
-android.c) to configure Emacs with this information.
-
-       /* Start the thread that runs Emacs.  */
-       thread = new EmacsThread (this, needDashQ);
-       thread.start ();
-
-Then, it allocates an ``EmacsThread'' object, and starts that thread.
-Inside that thread is where Emacs's C code runs.
-
-      }
-    catch (IOException exception)
-      {
-       EmacsNative.emacsAbort ();
-       return;
-
-And here is the purpose of the ``try'' block.  Functions related to
-file names in Java will signal errors of various types upon failure.
-
-This ``catch'' block means that the Java virtual machine will abort
-execution of the contents of the ``try'' block as soon as an error of
-type ``IOException'' is encountered, and begin executing the contents
-of the ``catch'' block.
-
-Any failure of that type here is a crash, and
-``EmacsNative.emacsAbort'' is called to quickly abort the process to
-get a useful backtrace.
-      }
-  }
-
-Now, let us look at the definition of the class ``EmacsThread'', found
-in org/gnu/emacs/EmacsThread.java:
-
-public class EmacsThread extends Thread
-{
-  /* Whether or not Emacs should be started -Q.         */
-  private boolean startDashQ;
-
-  public
-  EmacsThread (EmacsService service, boolean startDashQ)
-  {
-    super ("Emacs main thread");
-    this.startDashQ = startDashQ;
-  }
-
-  @Override
-  public void
-  run ()
-  {
-    String args[];
-
-    if (!startDashQ)
-      args = new String[] { "libandroid-emacs.so", };
-    else
-      args = new String[] { "libandroid-emacs.so", "-Q", };
-
-    /* Run the native code now.         */
-    EmacsNative.initEmacs (args, EmacsApplication.dumpFileName);
-  }
-};
-
-The class itself defines a single field, ``startDashQ'', a constructor
-with an unused argument of the type ``EmacsService'' (which is useful
-while debugging) and a flag ``startDashQ'', and a single function
-``run'', overriding the same function in the class ``Thread''.
-
-When ``thread.start'' is called, the Java virtual machine creates a
-new thread, and then calls the function ``run'' within that thread.
-
-This function then computes a suitable argument vector, and calls
-``EmacsNative.initEmacs'' (defined in android.c), which then calls a
-modified version of the regular Emacs ``main'' function.
-
-At that point, Emacs initialization proceeds as usual:
-Vinitial_window_system is set, loadup.el calls `normal-top-level',
-which calls `command-line', and finally
-`window-system-initialization', which initializes the `android'
-terminal interface as usual.
-
-What happens here is the same as on other platforms.  Now, here is
-what happens when the initial frame is created: Fx_create_frame calls
-`android_create_frame_window' to create a top level window:
-
-static void
-android_create_frame_window (struct frame *f)
-{
-  struct android_set_window_attributes attributes;
-  enum android_window_value_mask attribute_mask;
-
-  attributes.background_pixel = FRAME_BACKGROUND_PIXEL (f);
-  attribute_mask = ANDROID_CW_BACK_PIXEL;
-
-  block_input ();
-  FRAME_ANDROID_WINDOW (f)
-    = android_create_window (FRAME_DISPLAY_INFO (f)->root_window,
-                            f->left_pos,
-                            f->top_pos,
-                            FRAME_PIXEL_WIDTH (f),
-                            FRAME_PIXEL_HEIGHT (f),
-                            attribute_mask, &attributes);
-  unblock_input ();
-}
-
-This calls the function `android_create_window' with some arguments
-whose meanings are identical to the arguments to `XCreateWindow'.
-
-Here is the definition of `android_create_window', in android.c:
-
-android_window
-android_create_window (android_window parent, int x, int y,
-                      int width, int height,
-                      enum android_window_value_mask value_mask,
-                      struct android_set_window_attributes *attrs)
-{
-  static jclass class;
-  static jmethodID constructor;
-  jobject object, parent_object, old;
-  android_window window;
-  android_handle prev_max_handle;
-  bool override_redirect;
-
-What does it do? First, some context:
-
-At any time, there can be at most 65535 Java objects referred to by
-the rest of Emacs through the Java native interface.  Each such object
-is assigned a ``handle'' (similar to an XID on X) and given a unique
-type.  The function `android_resolve_handle' returns the JNI `jobject'
-associated with a given handle.
-
-  parent_object = android_resolve_handle (parent, ANDROID_HANDLE_WINDOW);
-
-Here, it is being used to look up the `jobject' associated with the
-`parent' handle.
-
-  prev_max_handle = max_handle;
-  window = android_alloc_id ();
-
-Next, `max_handle' is saved, and a new handle is allocated for
-`window'.
-
-  if (!window)
-    error ("Out of window handles!");
-
-An error is signalled if Emacs runs out of available handles.
-
-  if (!class)
-    {
-      class = (*android_java_env)->FindClass (android_java_env,
-                                             "org/gnu/emacs/EmacsWindow");
-      assert (class != NULL);
-
-Then, if this initialization has not yet been completed, Emacs
-proceeds to find the Java class named ``EmacsWindow''.
-
-      constructor
-       = (*android_java_env)->GetMethodID (android_java_env, class, "<init>",
-                                           "(SLorg/gnu/emacs/EmacsWindow;"
-                                           "IIIIZ)V");
-      assert (constructor != NULL);
-
-And it tries to look up the constructor, which should take seven
-arguments:
-
-  S                                    - a short.  (the handle ID)
-  Lorg/gnu/Emacs/EmacsWindow;          - an instance of the EmacsWindow
-                                         class.  (the parent)
-  IIII                                 - four ints.  (the window geometry.)
-  Z                                    - a boolean.  (whether or not the
-                                         window is override-redirect; see
-                                         XChangeWindowAttributes.)
-
-      old = class;
-      class = (*android_java_env)->NewGlobalRef (android_java_env, class);
-      (*android_java_env)->ExceptionClear (android_java_env);
-      ANDROID_DELETE_LOCAL_REF (old);
-
-Next, it saves a global reference to the class and deletes the local
-reference.  Global references will never be deallocated by the Java
-virtual machine as long as they still exist.
-
-      if (!class)
-       memory_full (0);
-    }
-
-  /* N.B. that ANDROID_CW_OVERRIDE_REDIRECT can only be set at window
-     creation time.  */
-  override_redirect = ((value_mask
-                       & ANDROID_CW_OVERRIDE_REDIRECT)
-                      && attrs->override_redirect);
-
-  object = (*android_java_env)->NewObject (android_java_env, class,
-                                          constructor, (jshort) window,
-                                          parent_object, (jint) x, (jint) y,
-                                          (jint) width, (jint) height,
-                                          (jboolean) override_redirect);
-
-Then, it creates an instance of the ``EmacsWindow'' class with the
-appropriate arguments and previously determined constructor.
-
-  if (!object)
-    {
-      (*android_java_env)->ExceptionClear (android_java_env);
-
-      max_handle = prev_max_handle;
-      memory_full (0);
-
-If creating the object fails, Emacs clears the ``pending exception''
-and signals that it is out of memory.
-    }
-
-  android_handles[window].type = ANDROID_HANDLE_WINDOW;
-  android_handles[window].handle
-    = (*android_java_env)->NewGlobalRef (android_java_env,
-                                        object);
-  (*android_java_env)->ExceptionClear (android_java_env);
-  ANDROID_DELETE_LOCAL_REF (object);
-
-Otherwise, it associates a new global reference to the object with the
-handle, and deletes the local reference returned from the JNI
-NewObject function.
-
-  if (!android_handles[window].handle)
-    memory_full (0);
-
-If allocating the global reference fails, Emacs signals that it is out
-of memory.
-
-  android_change_window_attributes (window, value_mask, attrs);
-  return window;
-
-Otherwise, it applies the specified window attributes and returns the
-handle of the new window.
-}
-
-
-
-DRAWABLES, CURSORS AND HANDLES
-
-Each widget created by Emacs corresponds to a single ``window'', which
-has its own backing store.  This arrangement is quite similar to X.
-
-C code does not directly refer to the EmacsView widgets that implement
-the UI logic behind windows.  Instead, its handles refer to
-EmacsWindow structures, which contain the state necessary to interact
-with the widgets in an orderly and synchronized manner.
-
-Like X, both pixmaps and windows are drawable resources, and the same
-graphics operations can be applied to both.  Thus, a separate
-EmacsPixmap structure is used to wrap around Android Bitmap resources,
-and the Java-level graphics operation functions are capable of
-operating on them both.
-
-Finally, graphics contexts are maintained on both the C and Java
-levels; the C state recorded in `struct android_gc' is kept in sync
-with the Java state in the GContext handle's corresponding EmacsGC
-structure, and cursors are used through handles that refer to
-EmacsCursor structures that hold system PointerIcons.
-
-In all cases, the interfaces provided are identical to X.
-
-
-
-EVENT LOOP
-
-In a typical Android application, the event loop is managed by the
-operating system, and callbacks (implemented through overriding
-separate functions in widgets) are run by the event loop wherever
-necessary.  The thread which runs the event loop is also the only
-thread capable of creating and manipulating widgets and activities,
-and is referred to as the ``UI thread''.
-
-These callbacks are used by Emacs to write representations of X-like
-events to a separate event queue, which are then read from Emacs's own
-event loop running in a separate thread.  This is accomplished through
-replacing `select' by a function which waits for the event queue to be
-occupied, in addition to any file descriptors that `select' would
-normally wait for.
-
-Conversely, Emacs's event loop sometimes needs to send events to the
-UI thread.  These events are implemented as tiny fragments of code,
-which are run as they are received by the main thread.
-
-A typical example is `displayToast', which is implemented in
-EmacsService.java:
-
-  public void
-  displayToast (final String string)
-  {
-    runOnUiThread (new Runnable () {
-       @Override
-       public void
-       run ()
-       {
-         Toast toast;
-
-         toast = Toast.makeText (getApplicationContext (),
-                                 string, Toast.LENGTH_SHORT);
-         toast.show ();
-       }
-      });
-  }
-
-Here, the variable `string' is used by a nested function.  This nested
-function contains a copy of that variable, and is run on the main
-thread using the function `runOnUiThread', in order to display a short
-status message on the display.
-
-When Emacs needs to wait for the nested function to finish, it uses a
-mechanism implemented in `syncRunnable'.  This mechanism first calls a
-deadlock avoidance mechanism, then runs a nested function on the UI
-thread, which is expected to signal itself as a condition variable
-upon completion.  It is typically used to allocate resources that can
-only be allocated from the UI thread, or to obtain non-thread-safe
-information.  The following function is an example; it returns a new
-EmacsView widget corresponding to the provided window:
-
-  public EmacsView
-  getEmacsView (final EmacsWindow window, final int visibility,
-               final boolean isFocusedByDefault)
-  {
-    Runnable runnable;
-    final EmacsHolder<EmacsView> view;
-
-    view = new EmacsHolder<EmacsView> ();
-
-    runnable = new Runnable () {
-       public void
-       run ()
-       {
-         synchronized (this)
-           {
-             view.thing = new EmacsView (window);
-             view.thing.setVisibility (visibility);
-
-             /* The following function is only present on Android 26
-                or later.  */
-             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
-               view.thing.setFocusedByDefault (isFocusedByDefault);
-
-             notify ();
-           }
-       }
-      };
-
-    syncRunnable (runnable);
-    return view.thing;
-  }
-
-As no value can be directly returned from the nested function, a
-separate container object is used to hold the result after the
-function finishes execution.  Note the type name inside the angle
-brackets: this type is substituted into the class definition as it is
-used; a definition such as:
-
-public class Foo<T>
-{
-  T bar;
-};
-
-can not be used alone:
-
-  Foo holder; /* Error! */
-
-but must have a type specified:
-
-  Foo<Object> holder;
-
-in which case the effective definition is:
-
-public class Foo
-{
-  Object bar;
-};
+Refer to the file `admin/notes/java' in the toplevel directory of the
+Emacs distribution or repository for specifics regarding writing Java
+code for Emacs and the organization of the Android port.
diff --git a/java/org/gnu/emacs/EmacsNative.java 
b/java/org/gnu/emacs/EmacsNative.java
index fae0ba98f86..a4b45aafbc1 100644
--- a/java/org/gnu/emacs/EmacsNative.java
+++ b/java/org/gnu/emacs/EmacsNative.java
@@ -196,6 +196,10 @@ public final class EmacsNative
      KEYCODE_VOLUME_MUTE should be forwarded to Emacs.  */
   public static native boolean shouldForwardMultimediaButtons ();
 
+  /* Return whether KEYCODE_SPACE combined with META_CTRL_MASK should
+     be prevented from reaching the system input method.  */
+  public static native boolean shouldForwardCtrlSpace ();
+
   /* Initialize the current thread, by blocking signals that do not
      interest it.  */
   public static native void setupSystemThread ();
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java 
b/java/org/gnu/emacs/EmacsOpenActivity.java
index ea503ebd120..ca6d99e20b7 100644
--- a/java/org/gnu/emacs/EmacsOpenActivity.java
+++ b/java/org/gnu/emacs/EmacsOpenActivity.java
@@ -477,6 +477,10 @@ public final class EmacsOpenActivity extends Activity
                      }
                  }
              }
+           else if (uri.getScheme ().equals ("org-protocol"))
+             /* URL is an org-protocol:// link, which is meant to be
+                directly relayed to emacsclient.  */
+             fileName = uri.toString ();
 
            if (fileName == null)
              {
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index 404796cd08c..05952f98cf1 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -643,13 +643,18 @@ public final class EmacsService extends Service
                                                          uri.getPath ());
              }
 
-           Log.d (TAG, ("browseUri: browsing " + url
-                        + " --> " + uri.getPath ()
-                        + " --> " + uri));
-
            intent = new Intent (Intent.ACTION_VIEW, uri);
+
+           /* Set several flags on the Intent prompting the system to
+              permit the recipient to read and edit the URI
+              indefinitely.  */
+
            intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK
-                            | Intent.FLAG_GRANT_READ_URI_PERMISSION);
+                            | Intent.FLAG_GRANT_READ_URI_PERMISSION
+                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+
+           if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
+             intent.addFlags (Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
          }
        else
          {
@@ -884,8 +889,6 @@ public final class EmacsService extends Service
                                        0);
     info = builder.build ();
 
-
-
     if (DEBUG_IC)
       Log.d (TAG, ("updateCursorAnchorInfo: " + x + " " + y
                   + " " + yBaseline + "-" + yBottom));
@@ -1137,8 +1140,10 @@ public final class EmacsService extends Service
     if (DEBUG_IC)
       Log.d (TAG, "updateExtractedText: @" + token + ", " + text);
 
+    icBeginSynchronous ();
     window.view.imManager.updateExtractedText (window.view,
                                               token, text);
+    icEndSynchronous ();
   }
 
 
diff --git a/java/org/gnu/emacs/EmacsView.java 
b/java/org/gnu/emacs/EmacsView.java
index 5a4bcbaa005..04c3d824027 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -470,6 +470,26 @@ public final class EmacsView extends ViewGroup
     surfaceView.setBitmap (bitmap, damageRect);
   }
 
+  @Override
+  public boolean
+  onKeyPreIme (int keyCode, KeyEvent event)
+  {
+    /* Several Android systems intercept key events representing
+       C-SPC.  Avert this by detecting C-SPC events here and relaying
+       them directly to onKeyDown.
+
+       Make this optional though, since some input methods also
+       leverage C-SPC as a shortcut for switching languages.  */
+
+    if ((keyCode == KeyEvent.KEYCODE_SPACE
+        && (window.eventModifiers (event)
+            & KeyEvent.META_CTRL_MASK) != 0)
+       && !EmacsNative.shouldForwardCtrlSpace ())
+      return onKeyDown (keyCode, event);
+
+    return super.onKeyPreIme (keyCode, event);
+  }
+
   @Override
   public boolean
   onKeyDown (int keyCode, KeyEvent event)
diff --git a/java/org/gnu/emacs/EmacsWindow.java 
b/java/org/gnu/emacs/EmacsWindow.java
index aff5046b22e..3738376a6f4 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -576,7 +576,7 @@ public final class EmacsWindow extends EmacsHandleObject
      input EVENT.  Replace bits corresponding to Left or Right keys
      with their corresponding general modifier bits.  */
 
-  private int
+  public static int
   eventModifiers (KeyEvent event)
   {
     int state;
diff --git a/lisp/bindings.el b/lisp/bindings.el
index 68aa0a78099..207adb3a2a4 100644
--- a/lisp/bindings.el
+++ b/lisp/bindings.el
@@ -794,7 +794,7 @@ meaningful if it refers to a lexically bound variable."
   "Describe minor mode for EVENT on minor modes area of the mode line."
   (interactive "@e")
   (let ((indicator (car (nth 4 (car (cdr event))))))
-    (describe-minor-mode-from-indicator indicator)))
+    (describe-minor-mode-from-indicator indicator event)))
 
 (defvar mode-line-defining-kbd-macro (propertize " Def" 'face 
'font-lock-warning-face)
   "String displayed in the mode line in keyboard macro recording mode.")
diff --git a/lisp/button.el b/lisp/button.el
index b01595943fc..bfe6ccc8d1f 100644
--- a/lisp/button.el
+++ b/lisp/button.el
@@ -492,7 +492,7 @@ pushing a button, use the `button-describe' command."
            (if str-button
                ;; mode-line, header-line, or display string event.
                (button-activate str t)
-              (if (eq (car pos) 'touchscreen-down)
+              (if (eq (car-safe pos) 'touchscreen-down)
                   ;; If touch-screen-track tap returns nil, then the
                   ;; tap was cancelled.
                   (when (touch-screen-track-tap pos)
diff --git a/lisp/edmacro.el b/lisp/edmacro.el
index 69d20d2bad3..bbf5a7f0495 100644
--- a/lisp/edmacro.el
+++ b/lisp/edmacro.el
@@ -179,7 +179,7 @@ With a prefix argument, format the macro in a more concise 
way."
         (setq-local edmacro-finish-hook finish-hook)
         (setq-local edmacro-store-hook store-hook)
         (setq-local font-lock-defaults
-                    '(edmacro-mode-font-lock-keywords nil nil nil nil))
+                    '(edmacro-mode-font-lock-keywords nil nil ((?\" . "w"))))
         (setq font-lock-multiline nil)
        (erase-buffer)
         (insert (substitute-command-keys
diff --git a/lisp/elec-pair.el b/lisp/elec-pair.el
index e101cbc9e6f..223c7d89773 100644
--- a/lisp/elec-pair.el
+++ b/lisp/elec-pair.el
@@ -153,7 +153,7 @@ return value is considered instead."
   :type '(choice (set (const :tag "Space" ?\s)
                       (const :tag "Tab" ?\t)
                       (const :tag "Newline" ?\n))
-                 (list character)))
+                 (repeat (character :value " "))))
 
 (defvar-local electric-pair-skip-whitespace-function
   #'electric-pair--skip-whitespace
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 3c4b6baca53..cf7b7c318f6 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -128,6 +128,14 @@
 ;; simple style rules to follow which checkdoc will auto-fix for you.
 ;; `y-or-n-p' and `yes-or-no-p' should also end in "?".
 ;;
+;; Lexical binding:
+;;
+;;   We recommend always using lexical binding in new code, and
+;; converting old code to use it.  Checkdoc warns if you don't have
+;; the recommended string "-*- lexical-binding: t -*-" at the top of
+;; the file.  You can disable this check with the user option
+;; `checkdoc-lexical-binding-flag'.
+;;
 ;; Adding your own checks:
 ;;
 ;;   You can experiment with adding your own checks by setting the
@@ -339,6 +347,12 @@ See Info node `(elisp) Documentation Tips' for background."
   :type 'boolean
   :version "28.1")
 
+(defcustom checkdoc-lexical-binding-flag t
+  "Non-nil means generate warnings if file is not using lexical binding.
+See Info node `(elisp) Converting to Lexical Binding' for more."
+  :type 'boolean
+  :version "30.1")
+
 ;; This is how you can use checkdoc to make mass fixes on the Emacs
 ;; source tree:
 ;;
@@ -1779,7 +1793,7 @@ function,command,variable,option or symbol." ms1))))))
                   (order (and (nth 3 fp) (car (nth 3 fp))))
                   (nocheck (append '("&optional" "&rest" "&key" "&aux"
                                       "&context" "&environment" "&whole"
-                                      "&body" "&allow-other-keys")
+                                      "&body" "&allow-other-keys" "nil")
                                     (nth 3 fp)))
                   (inopts nil))
               (while (and args found (> found last-pos))
@@ -2377,6 +2391,31 @@ Code:, and others referenced in the style guide."
              (point-min) (save-excursion (goto-char (point-min))
                                          (line-end-position))))
         nil))
+      (when checkdoc-lexical-binding-flag
+        (setq
+         err
+         ;; Lexical binding cookie.
+         (if (not (save-excursion
+                    (save-restriction
+                      (goto-char (point-min))
+                      (narrow-to-region (point) (pos-eol))
+                      (re-search-forward
+                       (rx "-*-" (* (* nonl) ";")
+                           (* space) "lexical-binding:" (* space) "t" (* space)
+                           (* ";" (* nonl))
+                           "-*-")
+                       nil t))))
+             (let ((pos (save-excursion (goto-char (point-min))
+                                        (goto-char (pos-eol))
+                                        (point))))
+               (if (checkdoc-y-or-n-p "There is no lexical-binding cookie!  
Add one?")
+                   (progn
+                     (goto-char pos)
+                     (insert "  -*- lexical-binding: t -*-"))
+                 (checkdoc-create-error
+                  "The first line should end with \"-*- lexical-binding: t 
-*-\""
+                  pos (1+ pos) t)))
+           nil)))
       (setq
        err
        (or
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 4cc43995c12..850fbc69180 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -3587,7 +3587,8 @@ possible.  Unlike regular macros, BODY can decide to 
\"punt\" and leave the
 original function call alone by declaring an initial `&whole foo' parameter
 and then returning foo."
   ;; Like `cl-defmacro', but with the `&whole' special case.
-  (declare (debug (&define name cl-macro-list
+  (declare (debug (&define [&name symbolp "@cl-compiler-macro"]
+                           cl-macro-list
                            cl-declarations-or-string def-body))
            (indent 2))
   (let ((p args) (res nil))
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index ad0077dadda..bb4552459dd 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -4177,7 +4177,8 @@ the deferred compilation mechanism."
              (symbols-with-pos-enabled t)
              ;; Have byte compiler signal an error when compilation fails.
              (byte-compile-debug t)
-             (comp-ctxt (make-comp-ctxt :output output
+             (comp-ctxt (make-comp-ctxt :output (when output
+                                                  (expand-file-name output))
                                         :with-late-load with-late-load)))
         (comp-log "\n\n" 1)
         (unwind-protect
diff --git a/lisp/emacs-lisp/disass.el b/lisp/emacs-lisp/disass.el
index dd59a2e02e1..73777d7e701 100644
--- a/lisp/emacs-lisp/disass.el
+++ b/lisp/emacs-lisp/disass.el
@@ -92,17 +92,16 @@ redefine OBJECT if it is a symbol."
                  (subr-native-elisp-p obj))
             (progn
               (require 'comp)
-              (call-process "objdump" nil (current-buffer) t "-S"
-                            (native-comp-unit-file (subr-native-comp-unit 
obj)))
+              (let ((eln (native-comp-unit-file (subr-native-comp-unit obj))))
+                (if (file-exists-p eln)
+                    (call-process "objdump" nil (current-buffer) t "-S" eln)
+                  (error "Missing eln file for #<subr %s>" name)))
               (goto-char (point-min))
-              (re-search-forward (concat "^.*"
+              (re-search-forward (concat "^.*<_?"
                                          (regexp-quote
-                                          (concat "<"
-                                                  (when (eq system-type 
'darwin)
-                                                    "_")
-                                                  (comp-c-func-name
-                                                   (subr-name obj) "F" t)
-                                                  ">:"))))
+                                          (comp-c-func-name
+                                           (subr-name obj) "F" t))
+                                         ">:"))
               (beginning-of-line)
               (delete-region (point-min) (point))
               (when (re-search-forward "^.*<.*>:" nil t 2)
diff --git a/lisp/emacs-lisp/edebug.el b/lisp/emacs-lisp/edebug.el
index 9a06807bcdc..78326fde26d 100644
--- a/lisp/emacs-lisp/edebug.el
+++ b/lisp/emacs-lisp/edebug.el
@@ -2469,12 +2469,52 @@ MSG is printed after `::::} '."
   (setf (cdr (assq 'edebug edebug-behavior-alist))
         '(edebug-default-enter edebug-fast-before edebug-fast-after)))
 
-(defalias 'edebug-before nil
+;; The following versions of `edebug-before' and `edebug-after' exist
+;; to handle the error which occurs if either of them gets called
+;; without an enclosing `edebug-enter'.  This can happen, for example,
+;; when a macro mistakenly has a `form' element in its edebug spec,
+;; and it additionally, at macro-expansion time, calls `eval',
+;; `apply', or `funcall' (etc.) on the corresponding argument.  This
+;; is intended to fix bug#65620.
+
+(defun edebug-b/a-error (func)
+  "Throw an error for an invalid call of FUNC.
+FUNC is expected to be `edebug-before' or `edebug-after'."
+  (let (this-macro
+        (n 0)
+        bt-frame)
+    (while (and (setq bt-frame (backtrace-frame n))
+                (not (and (car bt-frame)
+                          (memq (cadr bt-frame)
+                                '(macroexpand macroexpand-1)))))
+      (setq n (1+ n)))
+    (when bt-frame
+      (setq this-macro (caaddr bt-frame)))
+
+    (error
+     (concat "Invalid call to `" (symbol-name func) "'"
+             (if this-macro
+                 (concat ".  Is the edebug spec for `"
+                         (symbol-name this-macro)
+                         "' correct?")
+               ""   ; Not sure this case is possible (ACM, 2023-09-02)
+               )))))
+
+(defun edebug-before (_before-index)
   "Function called by Edebug before a form is evaluated.
-See `edebug-behavior-alist' for implementations.")
-(defalias 'edebug-after nil
+See `edebug-behavior-alist' for other implementations.  This
+version of `edebug-before' gets called when edebug is not yet set
+up.  `edebug-enter' binds the function cell to a real function
+when edebug becomes active."
+  (edebug-b/a-error 'edebug-before))
+
+(defun edebug-after (_before-index _after-index _form)
   "Function called by Edebug after a form is evaluated.
-See `edebug-behavior-alist' for implementations.")
+See `edebug-behavior-alist' for other implementations.  This
+version of `edebug-after' gets called when edebug is not yet set
+up.  `edebug-enter' binds the function cell to a real function
+when edebug becomes active."
+  (edebug-b/a-error 'edebug-after))
 
 (defun edebug--update-coverage (after-index value)
   (let ((old-result (aref edebug-coverage after-index)))
diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index a5e29dd5e3b..7adf92c11e0 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -411,7 +411,6 @@ The return value is the last VAL in the list.
 (gv-define-setter buffer-local-value (val var buf)
   (macroexp-let2 nil v val
     `(with-current-buffer ,buf (set (make-local-variable ,var) ,v))))
-(make-obsolete-generalized-variable 'buffer-local-value nil "29.1")
 
 (gv-define-expander alist-get
   (lambda (do key alist &optional default remove testfn)
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index b8737e5ccd2..a8393cb7e75 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -62,6 +62,18 @@
 (defconst package-vc--elpa-packages-version 1
   "Version number of the package specification format understood by 
package-vc.")
 
+(defconst package-vc--backend-type
+  `(choice :convert-widget
+           ,(lambda (widget)
+              (let (opts)
+                (dolist (be vc-handled-backends)
+                  (when (or (vc-find-backend-function be 'clone)
+                            (alist-get 'clone (get be 'vc-functions)))
+                    (push (widget-convert (list 'const be)) opts)))
+                (widget-put widget :args opts))
+              widget))
+  "The type of VC backends that support cloning package VCS repositories.")
+
 (defcustom package-vc-heuristic-alist
   `((,(rx bos "http" (? "s") "://"
           (or (: (? "www.") "github.com"
@@ -94,22 +106,27 @@
                  (+ (or alnum "-" "." "_")) (? "/")))
           eos)
      . Bzr))
-  "Heuristic mapping URL regular expressions to VC backends."
+  "Alist mapping repository URLs to VC backends.
+`package-vc-install' consults this alist to determine the VC
+backend from the repository URL when you call it without
+specifying a backend.  Each element of the alist has the form
+\(URL-REGEXP . BACKEND).  `package-vc-install' will use BACKEND of
+the first association for which the URL of the repository matches
+the URL-REGEXP of the association.  If no match is found,
+`package-vc-install' uses `package-vc-default-backend' instead."
   :type `(alist :key-type (regexp :tag "Regular expression matching URLs")
-                :value-type (choice :tag "VC Backend"
-                                    ,@(mapcar (lambda (b) `(const ,b))
-                                              vc-handled-backends)))
+                :value-type ,package-vc--backend-type)
   :version "29.1")
 
 (defcustom package-vc-default-backend 'Git
-  "Default VC backend used when cloning a package repository.
-If no repository type was specified or could be guessed by
-`package-vc-heuristic-alist', this is the default VC backend
-used as fallback.  The value must be a member of
-`vc-handled-backends' and the named backend must implement
-the `clone' function."
-  :type `(choice ,@(mapcar (lambda (b) (list 'const b))
-                           vc-handled-backends))
+  "Default VC backend to use for cloning package repositories.
+`package-vc-install' uses this backend when you specify neither
+the backend nor a repository URL that's recognized via
+`package-vc-heuristic-alist'.
+
+The value must be a member of `vc-handled-backends' that supports
+the `clone' VC function."
+  :type package-vc--backend-type
   :version "29.1")
 
 (defcustom package-vc-register-as-project t
@@ -140,20 +157,21 @@ the `clone' function."
                (package-desc-create :name name :kind 'vc))
            spec)))))))
 
-(defcustom package-vc-selected-packages '()
-  "List of packages that must be installed.
-Each member of the list is of the form (NAME . SPEC), where NAME
-is a symbol designating the package and SPEC is one of:
+
+(defcustom package-vc-selected-packages nil
+  "List of packages to install from their VCS repositories.
+Each element is of the form (NAME . SPEC), where NAME is a symbol
+designating the package and SPEC is one of:
 
 - nil, if any package version can be installed;
 - a version string, if that specific revision is to be installed;
-- a property list, describing a package specification.  For more
-  details, please consult the subsection \"Specifying Package
-  Sources\" in the Info node `(emacs)Fetching Package Sources'.
+- a property list, describing a package specification.  For possible
+  values, see the subsection \"Specifying Package Sources\" in the
+  Info node `(emacs)Fetching Package Sources'.
 
-This user option will be automatically updated to store package
-specifications for packages that are not specified in any
-archive."
+The command `package-vc-install' updates the value of this user
+option to store package specifications for packages that are not
+specified in any archive."
   :type '(alist :tag "List of packages you want to be installed"
                 :key-type (symbol :tag "Package")
                 :value-type
@@ -344,20 +362,27 @@ asynchronously."
         "\n")
        nil pkg-file nil 'silent))))
 
-(defcustom package-vc-allow-side-effects nil
-  "Whether to process :make and :shell-command spec arguments.
+(defcustom package-vc-allow-build-commands nil
+  "Whether to run extra build commands when installing VC packages.
+
+Some packages specify \"make\" targets or other shell commands
+that should run prior to building the package, by including the
+:make or :shell-command keywords in their specification.  By
+default, Emacs ignores these keywords when installing and
+upgrading VC packages, but if the value is a list of package
+names (symbols), the build commands will be run for those
+packages.  If the value is t, always respect :make and
+:shell-command keywords.
 
 It may be necessary to run :make and :shell-command arguments in
 order to initialize a package or build its documentation, but
 please be careful when changing this option, as installing and
 updating a package can run potentially harmful code.
 
-When set to a list of symbols (packages), run commands for only
-packages in the list.  When nil, never run commands.  Otherwise
-when non-nil, run commands for any package with :make or
-:shell-command specified.
-
-Package specs are loaded from trusted package archives."
+This applies to package specifications that come from your
+configured package archives, as well as from entries in
+`package-vc-selected-packages' and specifications that you give
+to `package-vc-install' directly."
   :type '(choice (const :tag "Run for all packages" t)
                  (repeat :tag "Run only for selected packages" (symbol :tag 
"Package name"))
                  (const :tag "Never run" nil))
@@ -388,42 +413,48 @@ otherwise it's assumed to be an Info file."
          (default-directory (package-desc-dir pkg-desc))
          (docs-directory (file-name-directory (expand-file-name file)))
          (output (expand-file-name (format "%s.info" pkg-name)))
+         (log-buffer (get-buffer-create (format " *package-vc doc: %s*" 
pkg-name)))
          clean-up)
-    (when (string-match-p "\\.org\\'" file)
-      (require 'ox)
-      (require 'ox-texinfo)
-      (with-temp-buffer
-        (insert-file-contents file)
-        (setq file (make-temp-file "ox-texinfo-"))
-        (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)
-      (cond
-       ((/= 0 (call-process "makeinfo" nil t nil
-                            "-I" docs-directory
-                            "--no-split" file
-                            "-o" output))
-        (message "Failed to build manual %s, see buffer %S"
-                 file (buffer-name)))
-       ((/= 0 (call-process "install-info" nil t nil
-                            output (expand-file-name "dir")))
-        (message "Failed to install manual %s, see buffer %S"
-                 output (buffer-name)))
-       ((kill-buffer))))
+    (with-current-buffer log-buffer
+      (erase-buffer))
+    (condition-case err
+        (progn
+          (when (string-match-p "\\.org\\'" file)
+            (require 'ox)
+            (require 'ox-texinfo)
+            (with-temp-buffer
+              (insert-file-contents file)
+              (setq file (make-temp-file "ox-texinfo-"))
+              (let ((default-directory docs-directory))
+                (org-export-to-file 'texinfo file))
+              (setq clean-up t)))
+          (cond
+           ((/= 0 (call-process "makeinfo" nil log-buffer nil
+                                "-I" docs-directory
+                                "--no-split" file
+                                "-o" output))
+            (message "Failed to build manual %s, see buffer %S"
+                     file (buffer-name)))
+           ((/= 0 (call-process "install-info" nil log-buffer nil
+                                output (expand-file-name "dir")))
+            (message "Failed to install manual %s, see buffer %S"
+                     output (buffer-name)))
+           ((kill-buffer log-buffer))))
+      (error (with-current-buffer log-buffer
+               (insert (error-message-string err)))
+             (message "Failed to export org manual for %s, see buffer %S" 
pkg-name log-buffer)))
     (when clean-up
       (delete-file file))))
 
-(defun package-vc-install-dependencies (requirements)
-  "Install missing dependencies, and return missing ones.
-The return value will be nil if everything was found, or a list
-of (NAME VERSION) pairs of all packages that couldn't be found.
+(defun package-vc-install-dependencies (deps)
+  "Install missing dependencies according to DEPS.
 
-REQUIREMENTS should be a list of additional requirements; each
-element in this list should have the form (PACKAGE VERSION-LIST),
-where PACKAGE is a package name and VERSION-LIST is the required
-version of that package."
+DEPS is a list of elements (PACKAGE VERSION-LIST), where
+PACKAGE is a package name and VERSION-LIST is the required
+version of that package.
+
+Return a list of dependencies that couldn't be met (or nil, when
+this function successfully installs all given dependencies)."
   (let ((to-install '()) (missing '()))
     (cl-labels ((search (pkg)
                   "Attempt to find all dependencies for PKG."
@@ -457,7 +488,7 @@ version of that package."
                   (let ((desc-a (package-desc-name a))
                         (desc-b (package-desc-name b)))
                     (depends-on-p desc-a desc-b))))
-      (mapc #'search requirements)
+      (mapc #'search deps)
       (cl-callf sort to-install #'version-order)
       (cl-callf seq-uniq to-install #'duplicate-p)
       (cl-callf sort to-install #'dependent-order))
@@ -523,9 +554,9 @@ documentation and marking the package as installed."
       (package-vc--generate-description-file pkg-desc pkg-file)
 
       ;; Process :make and :shell-command arguments before building 
documentation
-      (when (or (eq package-vc-allow-side-effects t)
+      (when (or (eq package-vc-allow-build-commands t)
                 (memq (package-desc-name pkg-desc)
-                      package-vc-allow-side-effects))
+                      package-vc-allow-build-commands))
         (package-vc--make pkg-spec pkg-desc))
 
       ;; Detect a manual
@@ -718,7 +749,10 @@ installed package."
 
 ;;;###autoload
 (defun package-vc-upgrade-all ()
-  "Attempt to upgrade all installed VC packages."
+  "Upgrade all installed VC packages.
+
+This may fail if the local VCS state of one of the packages
+conflicts with its remote repository state."
   (interactive)
   (dolist (package package-alist)
     (dolist (pkg-desc (cdr package))
@@ -728,7 +762,10 @@ installed package."
 
 ;;;###autoload
 (defun package-vc-upgrade (pkg-desc)
-  "Attempt to upgrade the package PKG-DESC."
+  "Upgrade the package described by PKG-DESC from package's VC repository.
+
+This may fail if the local VCS state of the package conflicts
+with the remote repository state."
   (interactive (list (package-vc--read-package-desc "Upgrade VC package: " t)))
   ;; HACK: To run `package-vc--unpack-1' after checking out the new
   ;; revision, we insert a hook into `vc-post-command-functions', and
@@ -791,34 +828,45 @@ If no such revision can be found, return nil."
 
 ;;;###autoload
 (defun package-vc-install (package &optional rev backend name)
-  "Fetch a PACKAGE and set it up for using with Emacs.
-
-If PACKAGE is a string containing an URL, download the package
-from the repository at that URL; the function will try to guess
-the name of the package from the URL.  This can be overridden by
-passing the optional argument NAME.  If PACKAGE is a cons-cell,
-it should have the form (NAME . SPEC), where NAME is a symbol
-indicating the package name and SPEC is a plist as described in
-`package-vc-selected-packages'.  Otherwise PACKAGE should be a
-symbol whose name is the package name, and the URL for the
-package will be taken from the package's metadata.
+  "Fetch a package described by PACKAGE and set it up for use with Emacs.
+
+PACKAGE specifies which package to install, where to find its
+source repository and how to build it.
+
+If PACKAGE is a symbol, install the package with that name
+according to metadata that package archives provide for it.  This
+is the simplest way to call this function, but it only works if
+the package you want to install is listed in a package archive
+you have configured.
+
+If PACKAGE is a string, it specifies the URL of the package
+repository.  In this case, optional argument BACKEND specifies
+the VC backend to use for cloning the repository; if it's nil,
+this function tries to infer which backend to use according to
+the value of `package-vc-heuristic-alist' and if that fails it
+uses `package-vc-default-backend'.  Optional argument NAME
+specifies the package name in this case; if it's nil, this
+package uses `file-name-base' on the URL to obtain the package
+name, otherwise NAME is the package name as a symbol.
+
+PACKAGE can also be a cons cell (PNAME . SPEC) where PNAME is the
+package name as a symbol, and SPEC is a plist that specifes how
+to fetch and build the package.  For possible values, see the
+subsection \"Specifying Package Sources\" in the Info
+node `(emacs)Fetching Package Sources'.
 
 By default, this function installs the last revision of the
 package available from its repository.  If REV is a string, it
-describes the revision to install, as interpreted by the VC
-backend.  The special value `:last-release' (interactively, the
-prefix argument), will use the commit of the latest release, if
-it exists.  The last release is the latest revision which changed
-the \"Version:\" header of the package's main Lisp file.
-
-Optional argument BACKEND specifies the VC backend to use for cloning
-the package's repository; this is only possible if NAME-OR-URL is a URL,
-a string.  If BACKEND is omitted or nil, the function
-uses `package-vc-heuristic-alist' to guess the backend.
-Note that by default, a VC package will be prioritized over a
-regular package, but it will not remove a VC package.
-
-\(fn PACKAGE &optional REV BACKEND)"
+describes the revision to install, as interpreted by the relevant
+VC backend.  The special value `:last-release' (interactively,
+the prefix argument), says to use the commit of the latest
+release, if it exists.  The last release is the latest revision
+which changed the \"Version:\" header of the package's main Lisp
+file.
+
+If you use this function to install a package that you also have
+installed from a package archive, the version this function
+installs takes precedence."
   (interactive
    (progn
      ;; Initialize the package system to get the list of package
@@ -894,7 +942,7 @@ for the last released version of the package."
 
 ;;;###autoload
 (defun package-vc-install-from-checkout (dir name)
-  "Set up the package NAME in DIR by linking it into the ELPA directory.
+  "Install the package NAME from its source directory DIR.
 Interactively, prompt the user for DIR, which should be a directory
 under version control, typically one created by `package-vc-checkout'.
 If invoked interactively with a prefix argument, prompt the user
@@ -936,13 +984,17 @@ prompt for the name of the package to rebuild."
 
 ;;;###autoload
 (defun package-vc-prepare-patch (pkg-desc subject revisions)
-  "Send patch for REVISIONS to maintainer of the package PKG using SUBJECT.
-The function uses `vc-prepare-patch', passing SUBJECT and
-REVISIONS directly.  PKG-DESC must be a package description.
+  "Email patches for REVISIONS to maintainer of package PKG-DESC using SUBJECT.
+
+PKG-DESC is a package descriptor and SUBJECT is the subject of
+the message.
+
 Interactively, prompt for PKG-DESC, SUBJECT, and REVISIONS.  When
 invoked with a numerical prefix argument, use the last N
 revisions.  When invoked interactively in a Log View buffer with
-marked revisions, use those."
+marked revisions, use those.
+
+See also `vc-prepare-patch'."
   (interactive
    (list (package-vc--read-package-desc "Package to prepare a patch for: " t)
          (and (not vc-prepare-patches-separately)
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index e1172d69bf0..3a019905960 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -1982,7 +1982,10 @@ Used to populate `package-selected-packages'."
 
 (defun package--save-selected-packages (&optional value)
   "Set and save `package-selected-packages' to VALUE."
-  (when value
+  (when (or value after-init-time)
+    ;; It is valid to set it to nil, for example when the last package
+    ;; is uninstalled.  But it shouldn't be done at init time, to
+    ;; avoid overwriting configurations that haven't yet been loaded.
     (setq package-selected-packages value))
   (if after-init-time
       (customize-save-variable 'package-selected-packages 
package-selected-packages)
@@ -2484,7 +2487,9 @@ Clean-up the corresponding .eln files if Emacs is native
 compiled."
   (when (featurep 'native-compile)
     (cl-loop
-     for file in (directory-files-recursively dir "\\.el\\'")
+     for file in (directory-files-recursively dir
+                                              ;; Exclude lockfiles
+                                              (rx bos (or (and "." (not "#")) 
(not ".")) (* nonl) ".el" eos))
      do (comp-clean-up-stale-eln (comp-el-to-eln-filename file))))
   (if (file-symlink-p (directory-file-name dir))
       (delete-file (directory-file-name dir))
diff --git a/lisp/emacs-lisp/syntax.el b/lisp/emacs-lisp/syntax.el
index d8f6c58f6ca..ba0c91d68c4 100644
--- a/lisp/emacs-lisp/syntax.el
+++ b/lisp/emacs-lisp/syntax.el
@@ -617,150 +617,150 @@ running the hook."
   (syntax-propertize pos)
   ;;
   (with-syntax-table (or syntax-ppss-table (syntax-table))
-  (let* ((cell (syntax-ppss--data))
-         (ppss-last (car cell))
-         (ppss-cache (cdr cell))
-         (old-ppss (cdr ppss-last))
-         (old-pos (car ppss-last))
-         (ppss nil)
-         (pt-min (point-min)))
-    (if (and old-pos (> old-pos pos)) (setq old-pos nil))
-    ;; Use the OLD-POS if usable and close.  Don't update the `last' cache.
-    (condition-case nil
-       (if (and old-pos (< (- pos old-pos)
-                           ;; The time to use syntax-begin-function and
-                           ;; find PPSS is assumed to be about 2 * distance.
-                           (let ((pair (aref syntax-ppss-stats 5)))
-                             (/ (* 2 (cdr pair)) (car pair)))))
-           (progn
-             (syntax-ppss--update-stats 0 old-pos pos)
-             (parse-partial-sexp old-pos pos nil nil old-ppss))
-
-         (cond
-          ;; Use OLD-PPSS if possible and close enough.
-          ((and (not old-pos) old-ppss
-                 ;; If `pt-min' is too far from `pos', we could try to use
-                ;; other positions in (nth 9 old-ppss), but that doesn't
-                ;; seem to happen in practice and it would complicate this
-                ;; code (and the before-change-function code even more).
-                ;; But maybe it would be useful in "degenerate" cases such
-                ;; as when the whole file is wrapped in a set
-                ;; of parentheses.
-                (setq pt-min (or (syntax-ppss-toplevel-pos old-ppss)
-                                 (nth 2 old-ppss)))
-                (<= pt-min pos) (< (- pos pt-min) syntax-ppss-max-span))
-           (syntax-ppss--update-stats 1 pt-min pos)
-           (setq ppss (parse-partial-sexp pt-min pos)))
-          ;; The OLD-* data can't be used.  Consult the cache.
-          (t
-           (let ((cache-pred nil)
-                 (cache ppss-cache)
-                 (pt-min (point-min))
-                 ;; I differentiate between PT-MIN and PT-BEST because
-                 ;; I feel like it might be important to ensure that the
-                 ;; cache is only filled with 100% sure data (whereas
-                 ;; syntax-begin-function might return incorrect data).
-                 ;; Maybe that's just stupid.
-                 (pt-best (point-min))
-                 (ppss-best nil))
-             ;; look for a usable cache entry.
-             (while (and cache (< pos (caar cache)))
-               (setq cache-pred cache)
-               (setq cache (cdr cache)))
-             (if cache (setq pt-min (caar cache) ppss (cdar cache)))
-
-             ;; Setup the before-change function if necessary.
-             (unless (or ppss-cache ppss-last)
-                ;; Note: combine-change-calls-1 needs to be kept in sync
-                ;; with this!
-               (add-hook 'before-change-functions
-                         #'syntax-ppss-flush-cache
-                          ;; We should be either the very last function on
-                          ;; before-change-functions or the very first on
-                          ;; after-change-functions.
-                          99 t))
-
-             ;; Use the best of OLD-POS and CACHE.
-             (if (or (not old-pos) (< old-pos pt-min))
-                 (setq pt-best pt-min ppss-best ppss)
-               (syntax-ppss--update-stats 4 old-pos pos)
-               (setq pt-best old-pos ppss-best old-ppss))
-
-             ;; Use the `syntax-begin-function' if available.
-             ;; We could try using that function earlier, but:
-             ;; - The result might not be 100% reliable, so it's better to use
-             ;;   the cache if available.
-             ;; - The function might be slow.
-             ;; - If this function almost always finds a safe nearby spot,
-             ;;   the cache won't be populated, so consulting it is cheap.
-             (when (and syntax-begin-function
-                        (progn (goto-char pos)
-                               (funcall syntax-begin-function)
-                               ;; Make sure it's better.
-                               (> (point) pt-best))
-                        ;; Simple sanity checks.
-                         (< (point) pos) ; backward-paragraph can fail here.
-                        (not (memq (get-text-property (point) 'face)
-                                   '(font-lock-string-face font-lock-doc-face
-                                     font-lock-comment-face))))
-               (syntax-ppss--update-stats 5 (point) pos)
-               (setq pt-best (point) ppss-best nil))
-
-             (cond
-              ;; Quick case when we found a nearby pos.
-              ((< (- pos pt-best) syntax-ppss-max-span)
-               (syntax-ppss--update-stats 2 pt-best pos)
-               (setq ppss (parse-partial-sexp pt-best pos nil nil ppss-best)))
-              ;; Slow case: compute the state from some known position and
-              ;; populate the cache so we won't need to do it again soon.
-              (t
-               (syntax-ppss--update-stats 3 pt-min pos)
-                (setq syntax-ppss--updated-cache t)
-
-               ;; If `pt-min' is too far, add a few intermediate entries.
-               (while (> (- pos pt-min) (* 2 syntax-ppss-max-span))
-                 (setq ppss (parse-partial-sexp
-                             pt-min (setq pt-min (/ (+ pt-min pos) 2))
-                             nil nil ppss))
-                  (push (cons pt-min ppss)
-                        (if cache-pred (cdr cache-pred) ppss-cache)))
-
-               ;; Compute the actual return value.
-               (setq ppss (parse-partial-sexp pt-min pos nil nil ppss))
-
-               ;; Debugging check.
-               ;; (let ((real-ppss (parse-partial-sexp (point-min) pos)))
-               ;;   (setcar (last ppss 4) 0)
-               ;;   (setcar (last real-ppss 4) 0)
-               ;;   (setcar (last ppss 8) nil)
-               ;;   (setcar (last real-ppss 8) nil)
-               ;;   (unless (equal ppss real-ppss)
-               ;;     (message "!!Syntax: %s != %s" ppss real-ppss)
-               ;;     (setq ppss real-ppss)))
-
-               ;; Store it in the cache.
-               (let ((pair (cons pos ppss)))
-                 (if cache-pred
-                     (if (> (- (caar cache-pred) pos) syntax-ppss-max-span)
-                         (push pair (cdr cache-pred))
-                       (setcar cache-pred pair))
-                   (if (or (null ppss-cache)
-                           (> (- (caar ppss-cache) pos)
-                              syntax-ppss-max-span))
-                       (push pair ppss-cache)
-                     (setcar ppss-cache pair)))))))))
-
-          (setq syntax-ppss--updated-cache t)
-         (setq ppss-last (cons pos ppss))
-          (setcar cell ppss-last)
-          (setcdr cell ppss-cache)
-         ppss)
-      (args-out-of-range
-       ;; If the buffer is more narrowed than when we built the cache,
-       ;; we may end up calling parse-partial-sexp with a position before
-       ;; point-min.  In that case, just parse from point-min assuming
-       ;; a nil state.
-       (parse-partial-sexp (point-min) pos))))))
+    (let* ((cell (syntax-ppss--data))
+           (ppss-last (car cell))
+           (ppss-cache (cdr cell))
+           (old-ppss (cdr ppss-last))
+           (old-pos (car ppss-last))
+           (ppss nil)
+           (pt-min (point-min)))
+      (if (and old-pos (> old-pos pos)) (setq old-pos nil))
+      ;; Use the OLD-POS if usable and close.  Don't update the `last' cache.
+      (condition-case nil
+          (if (and old-pos (< (- pos old-pos)
+                              ;; The time to use syntax-begin-function and
+                              ;; find PPSS is assumed to be about 2 * distance.
+                              (let ((pair (aref syntax-ppss-stats 5)))
+                                (/ (* 2 (cdr pair)) (car pair)))))
+              (progn
+                (syntax-ppss--update-stats 0 old-pos pos)
+                (parse-partial-sexp old-pos pos nil nil old-ppss))
+
+            (cond
+             ;; Use OLD-PPSS if possible and close enough.
+             ((and (not old-pos) old-ppss
+                   ;; If `pt-min' is too far from `pos', we could try to use
+                   ;; other positions in (nth 9 old-ppss), but that doesn't
+                   ;; seem to happen in practice and it would complicate this
+                   ;; code (and the before-change-function code even more).
+                   ;; But maybe it would be useful in "degenerate" cases such
+                   ;; as when the whole file is wrapped in a set
+                   ;; of parentheses.
+                   (setq pt-min (or (syntax-ppss-toplevel-pos old-ppss)
+                                    (nth 2 old-ppss)))
+                   (<= pt-min pos) (< (- pos pt-min) syntax-ppss-max-span))
+              (syntax-ppss--update-stats 1 pt-min pos)
+              (setq ppss (parse-partial-sexp pt-min pos)))
+             ;; The OLD-* data can't be used.  Consult the cache.
+             (t
+              (let ((cache-pred nil)
+                    (cache ppss-cache)
+                    (pt-min (point-min))
+                    ;; I differentiate between PT-MIN and PT-BEST because
+                    ;; I feel like it might be important to ensure that the
+                    ;; cache is only filled with 100% sure data (whereas
+                    ;; syntax-begin-function might return incorrect data).
+                    ;; Maybe that's just stupid.
+                    (pt-best (point-min))
+                    (ppss-best nil))
+                ;; look for a usable cache entry.
+                (while (and cache (< pos (caar cache)))
+                  (setq cache-pred cache)
+                  (setq cache (cdr cache)))
+                (if cache (setq pt-min (caar cache) ppss (cdar cache)))
+
+                ;; Setup the before-change function if necessary.
+                (unless (or ppss-cache ppss-last)
+                  ;; Note: combine-change-calls-1 needs to be kept in sync
+                  ;; with this!
+                  (add-hook 'before-change-functions
+                            #'syntax-ppss-flush-cache
+                            ;; We should be either the very last function on
+                            ;; before-change-functions or the very first on
+                            ;; after-change-functions.
+                            99 t))
+
+                ;; Use the best of OLD-POS and CACHE.
+                (if (or (not old-pos) (< old-pos pt-min))
+                    (setq pt-best pt-min ppss-best ppss)
+                  (syntax-ppss--update-stats 4 old-pos pos)
+                  (setq pt-best old-pos ppss-best old-ppss))
+
+                ;; Use the `syntax-begin-function' if available.
+                ;; We could try using that function earlier, but:
+                ;; - The result might not be 100% reliable, so it's better to 
use
+                ;;   the cache if available.
+                ;; - The function might be slow.
+                ;; - If this function almost always finds a safe nearby spot,
+                ;;   the cache won't be populated, so consulting it is cheap.
+                (when (and syntax-begin-function
+                           (progn (goto-char pos)
+                                  (funcall syntax-begin-function)
+                                  ;; Make sure it's better.
+                                  (> (point) pt-best))
+                           ;; Simple sanity checks.
+                           (< (point) pos) ; backward-paragraph can fail here.
+                           (not (memq (get-text-property (point) 'face)
+                                      '(font-lock-string-face 
font-lock-doc-face
+                                                              
font-lock-comment-face))))
+                  (syntax-ppss--update-stats 5 (point) pos)
+                  (setq pt-best (point) ppss-best nil))
+
+                (cond
+                 ;; Quick case when we found a nearby pos.
+                 ((< (- pos pt-best) syntax-ppss-max-span)
+                  (syntax-ppss--update-stats 2 pt-best pos)
+                  (setq ppss (parse-partial-sexp pt-best pos nil nil 
ppss-best)))
+                 ;; Slow case: compute the state from some known position and
+                 ;; populate the cache so we won't need to do it again soon.
+                 (t
+                  (syntax-ppss--update-stats 3 pt-min pos)
+                  (setq syntax-ppss--updated-cache t)
+
+                  ;; If `pt-min' is too far, add a few intermediate entries.
+                  (while (> (- pos pt-min) (* 2 syntax-ppss-max-span))
+                    (setq ppss (parse-partial-sexp
+                                pt-min (setq pt-min (/ (+ pt-min pos) 2))
+                                nil nil ppss))
+                    (push (cons pt-min ppss)
+                          (if cache-pred (cdr cache-pred) ppss-cache)))
+
+                  ;; Compute the actual return value.
+                  (setq ppss (parse-partial-sexp pt-min pos nil nil ppss))
+
+                  ;; Debugging check.
+                  ;; (let ((real-ppss (parse-partial-sexp (point-min) pos)))
+                  ;;   (setcar (last ppss 4) 0)
+                  ;;   (setcar (last real-ppss 4) 0)
+                  ;;   (setcar (last ppss 8) nil)
+                  ;;   (setcar (last real-ppss 8) nil)
+                  ;;   (unless (equal ppss real-ppss)
+                  ;;     (message "!!Syntax: %s != %s" ppss real-ppss)
+                  ;;     (setq ppss real-ppss)))
+
+                  ;; Store it in the cache.
+                  (let ((pair (cons pos ppss)))
+                    (if cache-pred
+                        (if (> (- (caar cache-pred) pos) syntax-ppss-max-span)
+                            (push pair (cdr cache-pred))
+                          (setcar cache-pred pair))
+                      (if (or (null ppss-cache)
+                              (> (- (caar ppss-cache) pos)
+                                 syntax-ppss-max-span))
+                          (push pair ppss-cache)
+                        (setcar ppss-cache pair)))))))))
+
+            (setq syntax-ppss--updated-cache t)
+            (setq ppss-last (cons pos ppss))
+            (setcar cell ppss-last)
+            (setcdr cell ppss-cache)
+            ppss)
+        (args-out-of-range
+         ;; If the buffer is more narrowed than when we built the cache,
+         ;; we may end up calling parse-partial-sexp with a position before
+         ;; point-min.  In that case, just parse from point-min assuming
+         ;; a nil state.
+         (parse-partial-sexp (point-min) pos))))))
 
 ;; Debugging functions
 
diff --git a/lisp/eshell/em-basic.el b/lisp/eshell/em-basic.el
index 016afe811b2..95d7d8f4ebe 100644
--- a/lisp/eshell/em-basic.el
+++ b/lisp/eshell/em-basic.el
@@ -188,6 +188,38 @@ or `eshell-printn' for display."
 
 (put 'eshell/umask 'eshell-no-numeric-conversions t)
 
+(defun eshell/eshell-debug (&rest args)
+  "A command for toggling certain debug variables."
+  (eshell-eval-using-options
+   "eshell-debug" args
+   '((?h "help" nil nil "display this usage message")
+     :usage "[KIND]...
+This command is used to aid in debugging problems related to Eshell
+itself.  It is not useful for anything else.  The recognized `kinds'
+are:
+
+   error       stops Eshell from trapping errors
+   form        shows command form manipulation in `*eshell last cmd*'
+   process     shows process events in `*eshell last cmd*'")
+   (if args
+       (dolist (kind args)
+         (if (equal kind "error")
+             (setq eshell-handle-errors (not eshell-handle-errors))
+           (let ((kind-sym (intern kind)))
+             (if (memq kind-sym eshell-debug-command)
+                 (setq eshell-debug-command
+                       (delq kind-sym eshell-debug-command))
+               (push kind-sym eshell-debug-command)))))
+     ;; Output the currently-enabled debug kinds.
+     (unless eshell-handle-errors
+       (eshell-print "errors\n"))
+     (dolist (kind eshell-debug-command)
+       (eshell-printn (symbol-name kind))))))
+
+(defun pcomplete/eshell-mode/eshell-debug ()
+  "Completion for the `debug' command."
+  (while (pcomplete-here '("error" "form" "process"))))
+
 (provide 'em-basic)
 
 ;; Local Variables:
diff --git a/lisp/eshell/em-dirs.el b/lisp/eshell/em-dirs.el
index 640d3676750..d62f36e56c2 100644
--- a/lisp/eshell/em-dirs.el
+++ b/lisp/eshell/em-dirs.el
@@ -253,26 +253,19 @@ Thus, this does not include the current directory.")
     (throw 'eshell-replace-command
           (eshell-parse-command "cd" (flatten-tree args)))))
 
-(defun eshell-expand-user-reference-1 (file)
+(defun eshell-expand-user-reference (file)
   "Expand a user reference in FILE to its real directory name."
   (replace-regexp-in-string
    (rx bos (group "~" (*? anychar)) (or "/" eos))
    #'expand-file-name file))
 
-(defun eshell-expand-user-reference (file)
-  "Expand a user reference in FILE to its real directory name.
-FILE can be either a string or a list of strings to expand."
-  ;; If the argument was a glob pattern, then FILE is a list, so
-  ;; expand each element of the glob's resulting list.
-  (if (listp file)
-      (mapcar #'eshell-expand-user-reference-1 file)
-    (eshell-expand-user-reference-1 file)))
-
 (defun eshell-parse-user-reference ()
   "An argument beginning with ~ is a filename to be expanded."
   (when (and (not eshell-current-argument)
              (eq (char-after) ?~))
-    (add-to-list 'eshell-current-modifiers #'eshell-expand-user-reference)
+    ;; Apply this modifier fairly early so it happens before things
+    ;; like glob expansion.
+    (add-hook 'eshell-current-modifiers #'eshell-expand-user-reference -50)
     (forward-char)
     (char-to-string (char-before))))
 
diff --git a/lisp/eshell/em-glob.el b/lisp/eshell/em-glob.el
index 1141b673e97..0d0ff6188b6 100644
--- a/lisp/eshell/em-glob.el
+++ b/lisp/eshell/em-glob.el
@@ -156,8 +156,8 @@ This mimics the behavior of zsh if non-nil, but bash if 
nil."
 (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))
+    (add-hook 'eshell-current-modifiers #'eshell-splice-args 99))
+  (add-hook 'eshell-current-modifiers #'eshell-extended-glob))
 
 (defun eshell-parse-glob-chars ()
   "Parse a globbing delimiter.
diff --git a/lisp/eshell/em-pred.el b/lisp/eshell/em-pred.el
index 1d67f1af990..ae7d0c43bc4 100644
--- a/lisp/eshell/em-pred.el
+++ b/lisp/eshell/em-pred.el
@@ -302,24 +302,14 @@ This function is specially for adding onto 
`eshell-parse-argument-hook'."
                   (preds (car modifiers))
                   (mods (cdr modifiers)))
               (when (or preds mods)
-                ;; Has to go at the end, which is only natural since
+                ;; Has to go near the end (but before
+                ;; `eshell-splice-args'), 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)))))))
+                (add-hook 'eshell-current-modifiers
+                          (lambda (lst)
+                            (eshell-apply-modifiers
+                             lst preds mods modifier-string))
+                          90))))
          (goto-char (1+ end))
          (eshell-finish-arg))))))
 
diff --git a/lisp/eshell/em-prompt.el b/lisp/eshell/em-prompt.el
index 42f8f273b52..15b849a4d37 100644
--- a/lisp/eshell/em-prompt.el
+++ b/lisp/eshell/em-prompt.el
@@ -50,22 +50,18 @@ as is common with most shells."
 (defcustom eshell-prompt-function
   (lambda ()
     (concat (abbreviate-file-name (eshell/pwd))
+            (unless (eshell-exit-success-p)
+              (format " [%d]" eshell-last-command-status))
             (if (= (file-user-uid) 0) " # " " $ ")))
-  "A function that returns the Eshell prompt string.
-Make sure to update `eshell-prompt-regexp' so that it will match your
-prompt."
+  "A function that returns the Eshell prompt string."
   :type 'function
   :group 'eshell-prompt)
 
 (defcustom eshell-prompt-regexp "^[^#$\n]* [#$] "
-  "A regexp which fully matches your Eshell prompt.
-This is useful for navigating by paragraph using \
-\\[forward-paragraph] and \\[backward-paragraph].
-
-If this variable is changed, all Eshell buffers must be exited
-and re-entered for it to take effect."
+  "A regexp which fully matches your Eshell prompt."
   :type 'regexp
   :group 'eshell-prompt)
+(make-obsolete-variable 'eshell-prompt-regexp nil "30.1")
 
 (defcustom eshell-highlight-prompt t
   "If non-nil, Eshell should highlight the prompt."
@@ -98,8 +94,10 @@ arriving, or after."
   :group 'eshell-prompt)
 
 (defvar-keymap eshell-prompt-mode-map
-  "C-c C-n" #'eshell-next-prompt
-  "C-c C-p" #'eshell-previous-prompt)
+  "C-c C-n"                      #'eshell-next-prompt
+  "C-c C-p"                      #'eshell-previous-prompt
+  "<remap> <forward-paragraph>"  #'eshell-forward-paragraph
+  "<remap> <backward-paragraph>" #'eshell-backward-paragraph)
 
 (defvar-keymap eshell-prompt-repeat-map
   :doc "Keymap to repeat eshell-prompt key sequences.  Used in `repeat-mode'."
@@ -119,11 +117,6 @@ arriving, or after."
   "Initialize the prompting code."
   (unless eshell-non-interactive-p
     (add-hook 'eshell-post-command-hook 'eshell-emit-prompt nil t)
-
-    (make-local-variable 'eshell-prompt-regexp)
-    (if eshell-prompt-regexp
-        (setq-local paragraph-start eshell-prompt-regexp))
-
     (eshell-prompt-mode)))
 
 (defun eshell-emit-prompt ()
@@ -172,16 +165,41 @@ negative, find the Nth next match."
   (interactive (eshell-regexp-arg "Backward input matching (regexp): "))
   (eshell-forward-matching-input regexp (- arg)))
 
-(defun eshell-next-prompt (n)
+(defun eshell-forward-paragraph (&optional n)
+  "Move to the beginning of the Nth next prompt in the buffer.
+Like `forward-paragraph', but navigates using fields."
+  (interactive "p")
+  (eshell-next-prompt n)
+  (goto-char (field-beginning (point) t)))
+
+(defun eshell-backward-paragraph (&optional n)
+  "Move to the beginning of the Nth previous prompt in the buffer.
+Like `backward-paragraph', but navigates using fields."
+  (interactive "p")
+  (eshell-previous-prompt n)
+  (goto-char (field-beginning (point) t)))
+
+(defun eshell-next-prompt (&optional n)
   "Move to end of Nth next prompt in the buffer."
   (interactive "p")
+  (unless n (setq n 1))
+  ;; First, move point to our starting position: the end of the
+  ;; current prompt (aka the beginning of the input), if any.  (The
+  ;; welcome message and output from commands don't count as having a
+  ;; current prompt.)
+  (pcase (get-text-property (point) 'field)
+    ('command-output)
+    ('prompt (goto-char (field-end)))
+    (_ (when-let ((match (text-property-search-backward 'field 'prompt t)))
+         (goto-char (prop-match-end match)))))
+  ;; Now, move forward/backward to our destination prompt.
   (if (natnump n)
       (while (and (> n 0)
                   (text-property-search-forward 'field 'prompt t))
         (setq n (1- n)))
     (let (match this-match)
-      ;; Don't count the current prompt.
-      (text-property-search-backward 'field 'prompt t)
+      ;; Go to the beginning of the current prompt.
+      (goto-char (field-beginning (point) t))
       (while (and (< n 0)
                   (setq this-match (text-property-search-backward
                                     'field 'prompt t)))
@@ -190,10 +208,10 @@ negative, find the Nth next match."
       (when match
         (goto-char (prop-match-end match))))))
 
-(defun eshell-previous-prompt (n)
+(defun eshell-previous-prompt (&optional n)
   "Move to end of Nth previous prompt in the buffer."
   (interactive "p")
-  (eshell-next-prompt (- n)))
+  (eshell-next-prompt (- (or n 1))))
 
 (defun eshell-skip-prompt ()
   "Skip past the text matching regexp `eshell-prompt-regexp'.
diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el
index 26be1127880..e9c6a7f2f68 100644
--- a/lisp/eshell/esh-arg.el
+++ b/lisp/eshell/esh-arg.el
@@ -293,10 +293,13 @@ then the result will be:
               (append (list 'eshell-concat eshell-current-quoted)
                       eshell-current-argument)))
       (setq eshell-arg-listified nil))
-    (while eshell-current-modifiers
+    (when eshell-current-modifiers
+      (eshell-debug-command 'form (format-message "applying modifiers %S"
+                                                  eshell-current-modifiers)
+                            eshell-current-argument))
+    (dolist (modifier eshell-current-modifiers)
       (setq eshell-current-argument
-           (list (car eshell-current-modifiers) eshell-current-argument)
-           eshell-current-modifiers (cdr eshell-current-modifiers))))
+            (list modifier eshell-current-argument))))
   (setq eshell-current-modifiers nil))
 
 (defun eshell-finish-arg (&rest arguments)
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 80066263396..ed2d6c71fc8 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -237,17 +237,6 @@ return non-nil if the command is complex."
   :version "24.1"                     ; removed eshell-cmd-initialize
   :type 'hook)
 
-(defcustom eshell-debug-command nil
-  "If non-nil, enable Eshell debugging code.
-This is slow, and only useful for debugging problems with Eshell.
-If you change this without using customize after Eshell has loaded,
-you must re-load `esh-cmd.el'."
-  :initialize 'custom-initialize-default
-  :set (lambda (symbol value)
-        (set symbol value)
-        (load "esh-cmd"))
-  :type 'boolean)
-
 (defcustom eshell-deferrable-commands
   '(eshell-named-command
     eshell-lisp-command
@@ -436,22 +425,9 @@ hooks should be run before and after the command."
                             (run-hooks 'eshell-post-command-hook)))
       (macroexp-progn commands))))
 
-(defun eshell-debug-command (tag subform)
-  "Output a debugging message to `*eshell last cmd*'."
-  (let ((buf (get-buffer-create "*eshell last cmd*"))
-       (text (eshell-stringify eshell-current-command)))
-    (with-current-buffer buf
-      (if (not tag)
-         (erase-buffer)
-       (insert "\n\C-l\n" tag "\n\n" text
-               (if subform
-                   (concat "\n\n" (eshell-stringify subform)) ""))))))
-
 (defun eshell-debug-show-parsed-args (terms)
   "Display parsed arguments in the debug buffer."
-  (ignore
-   (if eshell-debug-command
-       (eshell-debug-command "parsed arguments" terms))))
+  (ignore (eshell-debug-command 'form "parsed arguments" terms)))
 
 (defun eshell-no-command-conversion (terms)
   "Don't convert the command argument."
@@ -942,38 +918,6 @@ This avoids the need to use `let*'."
 ;; finishes, it will resume the evaluation using the remainder of the
 ;; command tree.
 
-(defun eshell/eshell-debug (&rest args)
-  "A command for toggling certain debug variables."
-  (ignore
-   (cond
-    ((not args)
-     (if eshell-handle-errors
-        (eshell-print "errors\n"))
-     (if eshell-debug-command
-        (eshell-print "commands\n")))
-    ((member (car args) '("-h" "--help"))
-     (eshell-print "usage: eshell-debug [kinds]
-
-This command is used to aid in debugging problems related to Eshell
-itself.  It is not useful for anything else.  The recognized `kinds'
-at the moment are:
-
-  errors       stops Eshell from trapping errors
-  commands     shows command execution progress in `*eshell last cmd*'
-"))
-    (t
-     (while args
-       (cond
-       ((string= (car args) "errors")
-        (setq eshell-handle-errors (not eshell-handle-errors)))
-       ((string= (car args) "commands")
-        (setq eshell-debug-command (not eshell-debug-command))))
-       (setq args (cdr args)))))))
-
-(defun pcomplete/eshell-mode/eshell-debug ()
-  "Completion for the `debug' command."
-  (while (pcomplete-here '("errors" "commands"))))
-
 (iter-defun eshell--find-subcommands (haystack)
   "Recursively search for subcommand forms in HAYSTACK.
 This yields the SUBCOMMANDs when found in forms like
@@ -1049,10 +993,7 @@ process(es) in a cons cell like:
                        (if here
                            (eshell-update-markers here))
                        (eshell-do-eval ',command))))
-    (and eshell-debug-command
-         (with-current-buffer (get-buffer-create "*eshell last cmd*")
-           (erase-buffer)
-           (insert "command: \"" input "\"\n")))
+    (eshell-debug-command-start input)
     (setq eshell-current-command command)
     (let* (result
            (delim (catch 'eshell-incomplete
@@ -1088,17 +1029,17 @@ process(es) in a cons cell like:
     (error
      (error (error-message-string err)))))
 
-(defmacro eshell-manipulate (tag &rest commands)
-  "Manipulate a COMMAND form, with TAG as a debug identifier."
-  (declare (indent 1))
-  ;; Check `bound'ness since at compile time the code until here has not
-  ;; executed yet.
-  (if (not (and (boundp 'eshell-debug-command) eshell-debug-command))
-      `(progn ,@commands)
-    `(progn
-       (eshell-debug-command ,(eval tag) form)
-       ,@commands
-       (eshell-debug-command ,(concat "done " (eval tag)) form))))
+(defmacro eshell-manipulate (form tag &rest body)
+  "Manipulate a command FORM with BODY, using TAG as a debug identifier."
+  (declare (indent 2))
+  (let ((tag-symbol (make-symbol "tag")))
+    `(if (not (memq 'form eshell-debug-command))
+         (progn ,@body)
+       (let ((,tag-symbol ,tag))
+         (eshell-debug-command 'form ,tag-symbol ,form 'always)
+         ,@body
+         (eshell-debug-command 'form (concat "done " ,tag-symbol) ,form
+                               'always)))))
 
 (defun eshell-do-eval (form &optional synchronous-p)
   "Evaluate FORM, simplifying it as we go.
@@ -1125,8 +1066,8 @@ have been replaced by constants."
     ;; we can modify any `let' forms to evaluate only once.
     (if (macrop (car form))
         (let ((exp (copy-tree (macroexpand form))))
-         (eshell-manipulate (format-message "expanding macro `%s'"
-                                            (symbol-name (car form)))
+          (eshell-manipulate form
+              (format-message "expanding macro `%s'" (symbol-name (car form)))
            (setcar form (car exp))
            (setcdr form (cdr exp)))))
     (let ((args (cdr form)))
@@ -1138,7 +1079,7 @@ have been replaced by constants."
         (let ((new-form (copy-tree `(let ((eshell--command-body nil)
                                           (eshell--test-body nil))
                                       (eshell--wrapped-while ,@args)))))
-          (eshell-manipulate "modifying while form"
+          (eshell-manipulate form "modifying while form"
             (setcar form (car new-form))
             (setcdr form (cdr new-form)))
           (eshell-do-eval form synchronous-p)))
@@ -1161,7 +1102,7 @@ have been replaced by constants."
           (setq eshell--command-body nil
                 eshell--test-body (copy-tree (car args)))))
        ((eq (car form) 'if)
-        (eshell-manipulate "evaluating if condition"
+        (eshell-manipulate form "evaluating if condition"
           (setcar args (eshell-do-eval (car args) synchronous-p)))
         (eshell-do-eval
          (cond
@@ -1180,7 +1121,7 @@ have been replaced by constants."
        (eval form))
        ((eq (car form) 'let)
         (unless (eq (car-safe (cadr args)) 'eshell-do-eval)
-          (eshell-manipulate "evaluating let args"
+          (eshell-manipulate form "evaluating let args"
             (dolist (letarg (car args))
               (when (and (listp letarg)
                          (not (eq (cadr letarg) 'quote)))
@@ -1207,7 +1148,7 @@ have been replaced by constants."
             ;; the let-bindings' values so that those values are
             ;; correct when we resume evaluation of this form.
             (when deferred
-              (eshell-manipulate "rebinding let args after `eshell-defer'"
+              (eshell-manipulate form "rebinding let args after `eshell-defer'"
                 (let ((bindings (car args)))
                   (while bindings
                     (let ((binding (if (consp (car bindings))
@@ -1232,7 +1173,7 @@ have been replaced by constants."
        (unless (eq (car form) 'unwind-protect)
          (setq args (cdr args)))
        (unless (eq (caar args) 'eshell-do-eval)
-         (eshell-manipulate "handling special form"
+          (eshell-manipulate form "handling special form"
            (setcar args `(eshell-do-eval ',(car args) ,synchronous-p))))
        (eval form))
        ((eq (car form) 'setq)
@@ -1242,7 +1183,7 @@ have been replaced by constants."
        (list 'quote (eval form)))
        (t
        (if (and args (not (memq (car form) '(run-hooks))))
-           (eshell-manipulate
+            (eshell-manipulate form
                (format-message "evaluating arguments to `%s'"
                                (symbol-name (car form)))
              (while args
@@ -1283,7 +1224,7 @@ have been replaced by constants."
                      (setq result (eval form))))))
            (if new-form
                (progn
-                 (eshell-manipulate "substituting replacement form"
+                  (eshell-manipulate form "substituting replacement form"
                    (setcar form (car new-form))
                    (setcdr form (cdr new-form)))
                  (eshell-do-eval form synchronous-p))
@@ -1292,7 +1233,7 @@ have been replaced by constants."
                        (procs (eshell-make-process-pair result)))
                   (if synchronous-p
                      (eshell/wait (cdr procs))
-                   (eshell-manipulate "inserting ignore form"
+                    (eshell-manipulate form "inserting ignore form"
                      (setcar form 'ignore)
                      (setcdr form nil))
                    (throw 'eshell-defer procs))
diff --git a/lisp/eshell/esh-io.el b/lisp/eshell/esh-io.el
index c07f871dd37..cd0cee6e21d 100644
--- a/lisp/eshell/esh-io.el
+++ b/lisp/eshell/esh-io.el
@@ -170,7 +170,7 @@ describing the mode, e.g. for using with 
`eshell-get-target'.")
 
 (defvar eshell-current-handles nil)
 
-(defvar eshell-last-command-status 0
+(defvar-local eshell-last-command-status 0
   "The exit code from the last command.  0 if successful.")
 
 (defvar eshell-last-command-result nil
diff --git a/lisp/eshell/esh-proc.el b/lisp/eshell/esh-proc.el
index 9c4036004ff..87719c019cb 100644
--- a/lisp/eshell/esh-proc.el
+++ b/lisp/eshell/esh-proc.el
@@ -332,6 +332,8 @@ Used only on systems which do not support async 
subprocesses.")
                :connection-type conn-type
                :stderr stderr-proc
                :file-handler t)))
+      (eshell-debug-command
+       'process (format-message "started external process `%s'" proc))
       (eshell-record-process-object proc)
       (eshell-record-process-properties proc)
       (run-hook-with-args 'eshell-exec-hook proc)
@@ -410,6 +412,9 @@ Used only on systems which do not support async 
subprocesses.")
   "Send the output from PROCESS (STRING) to the interactive display.
 This is done after all necessary filtering has been done."
   (when string
+    (eshell-debug-command
+     'process (format-message "received output from process `%s'\n\n%s"
+                              process string))
     (eshell--mark-as-output 0 (length string) string)
     (require 'esh-mode)
     (declare-function eshell-interactive-filter "esh-mode" (buffer string))
@@ -436,6 +441,9 @@ output."
                 (data (process-get proc :eshell-pending)))
             (process-put proc :eshell-pending nil)
             (process-put proc :eshell-busy t)
+            (eshell-debug-command
+             'process (format-message "received output from process `%s'\n\n%s"
+                                      proc string))
             (unwind-protect
                 (condition-case nil
                     (eshell-output-object data index handles)
@@ -460,6 +468,9 @@ output."
 (defun eshell-sentinel (proc string)
   "Generic sentinel for command processes.  Reports only signals.
 PROC is the process that's exiting.  STRING is the exit message."
+  (eshell-debug-command
+   'process (format-message "sentinel for external process `%s': %S"
+                            proc string))
   (when (buffer-live-p (process-buffer proc))
     (with-current-buffer (process-buffer proc)
       (unwind-protect
@@ -492,7 +503,11 @@ PROC is the process that's exiting.  STRING is the exit 
message."
                              status
                              (when status (list 'quote (= status 0)))
                              handles)
-                            (eshell-kill-process-function proc string)))))
+                            (eshell-kill-process-function proc string)
+                            (eshell-debug-command
+                             'process
+                             (format-message
+                              "finished external process `%s'" proc))))))
                 (funcall finish-io))))
         (when-let ((entry (assq proc eshell-process-list)))
           (eshell-remove-process-entry entry))))))
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index 87cd1f5dcb2..d5a75b0d715 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -102,6 +102,16 @@ argument matches `eshell-number-regexp'."
                                     (string :tag "Username")
                                     (repeat :tag "UIDs" string))))))
 
+(defcustom eshell-debug-command nil
+  "A list of debug features to enable when running Eshell commands.
+Possible entries are `form', to log the manipulation of Eshell
+command forms, and `process', to log external process operations.
+
+If nil, don't debug commands at all."
+  :version "30.1"
+  :type '(set (const :tag "Form manipulation" form)
+              (const :tag "Process operations" process)))
+
 ;;; Internal Variables:
 
 (defvar eshell-number-regexp
@@ -145,6 +155,9 @@ function `string-to-number'.")
                             ,#'eshell--mark-yanked-as-output))
   "A list of text properties to apply to command output.")
 
+(defvar eshell-debug-command-buffer "*eshell last cmd*"
+  "The name of the buffer to log debug messages about command invocation.")
+
 ;;; Obsolete variables:
 
 (define-obsolete-variable-alias 'eshell-host-names
@@ -164,11 +177,33 @@ function `string-to-number'.")
   "If `eshell-handle-errors' is non-nil, this is `condition-case'.
 Otherwise, evaluates FORM with no error handling."
   (declare (indent 2) (debug (sexp form &rest form)))
-  (if eshell-handle-errors
-      `(condition-case-unless-debug ,tag
-          ,form
-        ,@handlers)
-    form))
+  `(if eshell-handle-errors
+       (condition-case-unless-debug ,tag
+           ,form
+         ,@handlers)
+     ,form))
+
+(defun eshell-debug-command-start (command)
+  "Start debugging output for the command string COMMAND.
+If debugging is enabled (see `eshell-debug-command'), this will
+start logging to `*eshell last cmd*'."
+  (when eshell-debug-command
+    (with-current-buffer (get-buffer-create eshell-debug-command-buffer)
+      (erase-buffer)
+      (insert "command: \"" command "\"\n"))))
+
+(defmacro eshell-debug-command (kind message &optional form always)
+  "Output a debugging message to `*eshell last cmd*' if debugging is enabled.
+KIND is the kind of message to log (either `form' or `io').  If
+present in `eshell-debug-command' (or if ALWAYS is non-nil),
+output this message; otherwise, ignore it."
+  (let ((kind-sym (make-symbol "kind")))
+    `(let ((,kind-sym ,kind))
+       (when ,(or always `(memq ,kind-sym eshell-debug-command))
+         (with-current-buffer (get-buffer-create eshell-debug-command-buffer)
+           (insert "\n\C-l\n[" (symbol-name ,kind-sym) "] " ,message)
+           (when-let ((form ,form))
+             (insert "\n\n" (eshell-stringify form))))))))
 
 (defun eshell--mark-as-output (start end &optional object)
   "Mark the text from START to END as Eshell output.
@@ -326,7 +361,7 @@ as the $PATH was actually specified."
                  (eshell-under-windows-p))
         (push "." path))
       (if (and remote (not literal-p))
-          (mapcar (lambda (x) (file-name-concat remote x)) path)
+          (mapcar (lambda (x) (concat remote x)) path)
         path))))
 
 (defun eshell-set-path (path)
diff --git a/lisp/eshell/eshell.el b/lisp/eshell/eshell.el
index 15fc2ae6310..a3f80f453eb 100644
--- a/lisp/eshell/eshell.el
+++ b/lisp/eshell/eshell.el
@@ -301,7 +301,8 @@ argument), then insert output into the current buffer at 
point."
                     `(let ((eshell-current-handles
                             (eshell-create-handles ,stdout 'insert))
                            (eshell-current-subjob-p))
-                      ,(eshell-parse-command command))))
+                      ,(eshell-parse-command command))
+                    command))
             intr
             (bufname (if (eq (car-safe proc) :eshell-background)
                          "*Eshell Async Command Output*"
@@ -356,6 +357,7 @@ corresponding to a successful execution."
     (with-temp-buffer
       (let ((eshell-non-interactive-p t))
        (eshell-mode)
+        (eshell-debug-command-start command)
        (let ((result (eshell-do-eval
                       (list 'eshell-commands
                             (list 'eshell-command-to-value
diff --git a/lisp/filesets.el b/lisp/filesets.el
index 81a194a45e6..639b108ac03 100644
--- a/lisp/filesets.el
+++ b/lisp/filesets.el
@@ -413,15 +413,14 @@ directory's name.
 
 Note: You have to manually rebuild the menu if you change this value."
   :set #'filesets-set-default
-  :type '(choice :tag "Function:"
+  :type '(choice :tag "Function"
                 (const :tag "dired"
                        :value dired)
                 (list :tag "Command"
                       :value ("" "%s")
                       (string :tag "Name")
                       (string :tag "Arguments"))
-                (function :tag "Function"
-                          :value nil)))
+                 (function :tag "Function")))
 
 (defcustom filesets-open-file-function #'filesets-find-or-display-file
   "The function used for opening files.
@@ -437,23 +436,21 @@ readable, will not be opened.
 
 Caveat: Changes will take effect only after rebuilding the menu."
   :set #'filesets-set-default
-  :type '(choice :tag "Function:"
+  :type '(choice :tag "Function"
                 (const :tag "filesets-find-or-display-file"
                        :value filesets-find-or-display-file)
                 (const :tag "filesets-find-file"
                        :value filesets-find-file)
-                (function :tag "Function"
-                          :value nil)))
+                 (function :tag "Function")))
 
 (defcustom filesets-save-buffer-function #'save-buffer
   "The function used to save a buffer.
 Caveat: Changes will take effect after rebuilding the menu."
   :set #'filesets-set-default
-  :type '(choice :tag "Function:"
+  :type '(choice :tag "Function"
                 (const :tag "save-buffer"
                        :value save-buffer)
-                (function :tag "Function"
-                          :value nil)))
+                 (function :tag "Function")))
 
 (defcustom filesets-find-file-delay
   (if (and (featurep 'xemacs) gutter-buffers-tab-visible-p)
@@ -535,7 +532,7 @@ the filename."
   :type '(repeat :tag "Commands"
                 (list :tag "Definition" :value ("")
                       (string "Name")
-                      (choice :tag "Command"
+                       (choice :tag "Command" :value ""
                               (string :tag "String")
                               (function :tag "Function"))
                       (repeat :tag "Argument List"
@@ -546,8 +543,7 @@ the filename."
                                               :value "<file-name>")
                                       (string :tag "Quoted File Name"
                                               :value "<<file-name>>")
-                                      (function :tag "Function"
-                                                 :value nil))))))
+                                       (function :tag "Function"))))))
 
 (defcustom filesets-external-viewers
   (let
@@ -647,12 +643,12 @@ In order to view pdf or rtf files in an Emacs buffer, you 
could use these:
                       (repeat :tag "Properties"
                               (choice
                                (list :tag ":constraintp"
-                                     :value (:constraintp)
+                                      :value (:constraintp ignore)
                                      (const :format ""
                                             :value :constraintp)
                                      (function :tag "Function"))
                                (list :tag ":constraint-flag (obsolete)"
-                                     :value (:constraint-flag)
+                                      :value (:constraint-flag nil)
                                      (const :format ""
                                             :value :constraint-flag)
                                      (sexp :tag "Symbol"))
@@ -667,7 +663,7 @@ In order to view pdf or rtf files in an Emacs buffer, you 
could use these:
                                              :value :ignore-on-read-text)
                                      (boolean :tag "Boolean"))
                                (list :tag ":args"
-                                     :value (:args)
+                                      :value (:args nil)
                                      (const :format ""
                                             :value :args)
                                      (repeat :tag "List"
@@ -676,10 +672,9 @@ In order to view pdf or rtf files in an Emacs buffer, you 
could use these:
                                                              :value "")
                                                      (symbol :tag "Symbol"
                                                              :value nil)
-                                                     (function :tag "Function"
-                                                               :value nil))))
+                                                      (function :tag 
"Function"))))
                                (list :tag ":open-hook"
-                                     :value (:open-hook)
+                                      :value (:open-hook nil)
                                      (const :format ""
                                             :value :open-hook)
                                      (hook :tag "Hook"))
diff --git a/lisp/frame.el b/lisp/frame.el
index ba5d1caafa2..2452f7f8d4a 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -2906,7 +2906,7 @@ Values smaller than 0.2 sec are treated as 0.2 sec."
   "How many times to blink before using a solid cursor on NS, X, and 
MS-Windows.
 Use 0 or negative value to blink forever."
   :version "24.4"
-  :type 'natnum
+  :type 'integer
   :group 'cursor)
 
 (defvar blink-cursor-blinks-done 1
diff --git a/lisp/help-fns.el b/lisp/help-fns.el
index 609bed18f2f..b34778773a9 100644
--- a/lisp/help-fns.el
+++ b/lisp/help-fns.el
@@ -369,7 +369,8 @@ if the variable `help-downcase-arguments' is non-nil."
       (setq doc (replace-regexp-in-string
                  ;; This is heuristic, but covers all common cases
                  ;; except ARG1-ARG2
-                 (concat "\\<"                   ; beginning of word
+                 (concat "([^ ]+ .*"             ; skip function name
+                         "\\<"                   ; beginning of word
                          "\\(?:[a-z-]*-\\)?"     ; for xxx-ARG
                          "\\("
                          (regexp-quote arg)
diff --git a/lisp/help.el b/lisp/help.el
index f522cfac2a1..a012086a687 100644
--- a/lisp/help.el
+++ b/lisp/help.el
@@ -1230,15 +1230,60 @@ appeared on the mode-line."
                      i))))
                minor-mode-alist)))
 
-(defun describe-minor-mode-from-indicator (indicator)
+(defun describe-minor-mode-from-indicator (indicator &optional event)
   "Display documentation of a minor mode specified by INDICATOR.
 If you call this function interactively, you can give indicator which
-is currently activated with completion."
+is currently activated with completion.
+
+If non-nil, EVENT is a mouse event used to establish which minor
+mode lighter was clicked."
   (interactive (list
                (completing-read
                 "Minor mode indicator: "
                 (describe-minor-mode-completion-table-for-indicator))))
-  (let ((minor-mode (lookup-minor-mode-from-indicator indicator)))
+  (when (and event mode-line-compact)
+    (let* ((event-start (event-start event))
+           (window (posn-window event-start)))
+      ;; If INDICATOR is a string object, WINDOW is set, and
+      ;; `mode-line-compact' might be enabled, find a string in
+      ;; `minor-mode-alist' that is present within the INDICATOR and
+      ;; whose extents within INDICATOR contain the position of the
+      ;; object within the string.
+      (when (windowp window)
+        (setq indicator (posn-object event-start))
+        (catch 'found
+          (with-selected-window window
+            (let ((alist minor-mode-alist) string position)
+              (when (consp indicator)
+                (with-temp-buffer
+                  (insert (car indicator))
+                  (dolist (menu alist)
+                    ;; If this is a valid minor mode menu entry,
+                    (when (and (consp menu)
+                               (setq string (format-mode-line (cadr menu)
+                                                              nil window))
+                               (> (length string) 0))
+                      ;; Start searching for an appearance of (cdr
+                      ;; menu).
+                      (goto-char (point-min))
+                      (while (search-forward string nil 0)
+                        ;; If the position of the string object is
+                        ;; contained within, set indicator to the
+                        ;; minor mode in question.
+                        (setq position (1+ (cdr indicator)))
+                        (and (>= position (match-beginning 0))
+                             (<= position (match-end 0))
+                             (setq indicator (car menu))
+                             (throw 'found nil)))))))))))))
+  ;; If INDICATOR is still a cons, use its car.
+  (when (consp indicator)
+    (setq indicator (car indicator)))
+  (let ((minor-mode (if (symbolp indicator)
+                        ;; indicator being set to a symbol means that
+                        ;; the loop above has already found a
+                        ;; matching minor mode.
+                        indicator
+                      (lookup-minor-mode-from-indicator indicator))))
     (if minor-mode
        (describe-minor-mode-from-symbol minor-mode)
       (error "Cannot find minor mode for `%s'" indicator))))
@@ -1463,10 +1508,11 @@ Otherwise, return a new string."
         (buffer-string)))))
 
 (defun substitute-quotes (string)
-  "Substitute quote characters for display.
+  "Substitute quote characters in STRING for display.
 Each grave accent \\=` is replaced by left quote, and each
-apostrophe \\=' is replaced by right quote.  Left and right quote
-characters are specified by `text-quoting-style'."
+apostrophe \\=' is replaced by right quote.  Which left and right
+quote characters to use is determined by the variable
+`text-quoting-style'."
   (cond ((eq (text-quoting-style) 'curve)
          (string-replace "`" "‘"
                          (string-replace "'" "’" string)))
diff --git a/lisp/image-mode.el b/lisp/image-mode.el
index 713125d4e58..dce35ff72da 100644
--- a/lisp/image-mode.el
+++ b/lisp/image-mode.el
@@ -89,7 +89,7 @@ This will always keep the image fit to the window.
 When non-nil, the value should be a number of seconds to wait before
 resizing according to the value specified in `image-auto-resize'."
   :type '(choice (const :tag "No auto-resize on window size change" nil)
-                 (integer :tag "Wait for number of seconds before resize" 1))
+                 (number :tag "Wait for number of seconds before resize" 1))
   :version "27.1"
   :group 'image)
 
diff --git a/lisp/international/emoji.el b/lisp/international/emoji.el
index 856c405b545..2deb44c6412 100644
--- a/lisp/international/emoji.el
+++ b/lisp/international/emoji.el
@@ -97,7 +97,7 @@ representing names.  For instance:
                        (multisession-value emoji--recent)))
 
 ;;;###autoload (autoload 'emoji-search "emoji" nil t)
-(transient-define-prefix emoji-search ()
+(transient-define-prefix emoji-search (glyph derived)
   "Choose and insert an emoji glyph by typing its Unicode name.
 This command prompts for an emoji name, with completion, and
 inserts it.  It recognizes the Unicode Standard names of emoji,
@@ -106,15 +106,17 @@ and also consults the `emoji-alternate-names' alist."
   [:class transient-columns
    :setup-children emoji--setup-suffixes
    :description emoji--group-description]
-  (interactive "*")
-  (emoji--init)
-  (pcase-let ((`(,glyph . ,derived) (emoji--read-emoji)))
-    (if derived
-        (emoji--setup-prefix 'emoji-search "Choose Emoji"
-                             (list glyph)
-                             (cons glyph derived))
-      (emoji--add-recent glyph)
-      (insert glyph))))
+  (interactive
+   (progn (barf-if-buffer-read-only)
+          (emoji--init)
+          (let ((cons (emoji--read-emoji)))
+            (list (car cons) (cdr cons)))))
+  (if derived
+      (emoji--setup-prefix 'emoji-search "Choose Emoji"
+                           (list glyph)
+                           (cons glyph derived))
+    (emoji--add-recent glyph)
+    (insert glyph)))
 
 (defclass emoji--narrow (transient-suffix)
   ((title :initarg :title)
@@ -142,12 +144,15 @@ and also consults the `emoji-alternate-names' alist."
 (defun emoji--group-description ()
   (car (oref transient--prefix scope)))
 
-(transient-define-suffix emoji-insert-glyph ()
+(transient-define-suffix emoji-insert-glyph (glyph)
   "Insert the emoji you selected."
-  (interactive nil not-a-mode)
-  (let ((glyph (oref (transient-suffix-object) description)))
-    (emoji--add-recent glyph)
-    (insert glyph)))
+  (interactive
+   (list (if (string-prefix-p "emoji-" (symbol-name transient-current-command))
+             (oref (transient-suffix-object) description)
+           (car (multisession-value emoji--recent))))
+   not-a-mode)
+  (emoji--add-recent glyph)
+  (insert glyph))
 
 ;;;###autoload
 (defun emoji-list ()
diff --git a/lisp/jit-lock.el b/lisp/jit-lock.el
index 452cbd1ca51..d0522d6a791 100644
--- a/lisp/jit-lock.el
+++ b/lisp/jit-lock.el
@@ -1,6 +1,6 @@
 ;;; jit-lock.el --- just-in-time fontification  -*- lexical-binding: t -*-
 
-;; Copyright (C) 1998, 2000-2023 Free Software Foundation, Inc.
+;; Copyright (C) 1998-2023 Free Software Foundation, Inc.
 
 ;; Author: Gerd Moellmann <gerd@gnu.org>
 ;; Keywords: faces files
@@ -90,7 +90,8 @@ See also `jit-lock-stealth-nice'."
   :type 'boolean)
 
 
-(defvaralias 'jit-lock-defer-contextually 'jit-lock-contextually)
+(define-obsolete-variable-alias 'jit-lock-defer-contextually
+  'jit-lock-contextually "30.1")
 (defcustom jit-lock-contextually 'syntax-driven
   "If non-nil, fontification should be syntactically true.
 If nil, refontification occurs only on lines that were modified.  This
diff --git a/lisp/loadhist.el b/lisp/loadhist.el
index eb87016695c..3800ea70ea4 100644
--- a/lisp/loadhist.el
+++ b/lisp/loadhist.el
@@ -1,6 +1,6 @@
 ;;; loadhist.el --- lisp functions for working with feature groups  -*- 
lexical-binding: t -*-
 
-;; Copyright (C) 1995, 1998, 2000-2023 Free Software Foundation, Inc.
+;; Copyright (C) 1995-2023 Free Software Foundation, Inc.
 
 ;; Author: Eric S. Raymond <esr@thyrsus.com>
 ;; Maintainer: emacs-devel@gnu.org
@@ -108,7 +108,8 @@ from a file."
                               features))
                      features)))))
 
-(defvaralias 'loadhist-hook-functions 'unload-feature-special-hooks)
+(define-obsolete-variable-alias 'loadhist-hook-functions
+  'unload-feature-special-hooks "30.1")
 (defvar unload-feature-special-hooks
   '(after-change-functions after-insert-file-functions
     after-make-frame-functions auto-coding-functions
diff --git a/lisp/loadup.el b/lisp/loadup.el
index dab8579be24..b468cab276c 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -248,7 +248,7 @@
 (load "simple")
 (load "emacs-lisp/seq")
 (load "emacs-lisp/nadvice")
-(load "minibuffer") ;Needs cl-generic (and define-minor-mode).
+(load "minibuffer") ; Needs cl-generic, seq (and define-minor-mode).
 (load "frame")
 (load "startup")
 (load "term/tty-colors")
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 0f6220d519d..a7e17686df4 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -153,19 +153,6 @@ The metadata of a completion table should be constant 
between two boundaries."
 (defun completion-metadata-get (metadata prop)
   (cdr (assq prop metadata)))
 
-(defun completion--some (fun xs)
-  "Apply FUN to each element of XS in turn.
-Return the first non-nil returned value.
-Like CL's `some'."
-  (let ((firsterror nil)
-        res)
-    (while (and (not res) xs)
-      (condition-case-unless-debug err
-          (setq res (funcall fun (pop xs)))
-        (error (unless firsterror (setq firsterror err)) nil)))
-    (or res
-        (if firsterror (signal (car firsterror) (cdr firsterror))))))
-
 (defun complete-with-action (action collection string predicate)
   "Perform completion according to ACTION.
 STRING, COLLECTION and PREDICATE are used as in `try-completion'.
@@ -428,9 +415,9 @@ obeys predicates."
   ;; is returned by TABLE2 (because TABLE1 returned an empty list).
   ;; Same potential problem if any of the tables use quoting.
   (lambda (string pred action)
-    (completion--some (lambda (table)
-                        (complete-with-action action table string pred))
-                      tables)))
+    (seq-some (lambda (table)
+                (complete-with-action action table string pred))
+              tables)))
 
 (defun completion-table-merge (&rest tables)
   "Create a completion table that collects completions from all TABLES."
@@ -453,9 +440,9 @@ obeys predicates."
                                 (all-completions string table pred))
                               tables)))
      (t
-      (completion--some (lambda (table)
-                          (complete-with-action action table string pred))
-                        tables)))))
+      (seq-some (lambda (table)
+                  (complete-with-action action table string pred))
+                tables)))))
 
 (defun completion-table-with-quoting (table unquote requote)
   ;; A difficult part of completion-with-quoting is to map positions in the
@@ -1218,7 +1205,7 @@ overrides the default specified in 
`completion-category-defaults'."
               (cl-assert (<= point (length string)))
               (pop new))))
          (result-and-style
-          (completion--some
+          (seq-some
            (lambda (style)
              (let ((probe (funcall
                            (or (nth n (assq style completion-styles-alist))
diff --git a/lisp/net/browse-url.el b/lisp/net/browse-url.el
index daa46baf8f2..202df496b99 100644
--- a/lisp/net/browse-url.el
+++ b/lisp/net/browse-url.el
@@ -236,7 +236,7 @@ be used instead."
 
 (defcustom browse-url-button-regexp
   (concat
-   "\\b\\(\\(www\\.\\|\\(s?https?\\|ftp\\|file\\|gopher\\|gemini\\|"
+   "\\b\\(\\(www\\.\\|\\(s?https?\\|ftps?\\|file\\|gophers?\\|gemini\\|"
    "nntp\\|news\\|telnet\\|wais\\|mailto\\|info\\):\\)"
    "\\(//[-a-z0-9_.]+:[0-9]*\\)?"
    (let ((chars "-a-z0-9_=#$@~%&*+\\/[:word:]")
@@ -1457,8 +1457,7 @@ used instead of `browse-url-new-window-flag'."
 
 ;;;###autoload
 (defun browse-url-w3-gnudoit (url &optional _new-window)
-  ;; new-window ignored
-  "Ask another Emacs running gnuserv to load the URL using the W3 browser.
+  "Ask another Emacs running emacsclient to load the URL using the W3 browser.
 The `browse-url-gnudoit-program' program is used with options given by
 `browse-url-gnudoit-args'.  Default to the URL around or before point."
   (declare (obsolete nil "25.1"))
diff --git a/lisp/net/newst-backend.el b/lisp/net/newst-backend.el
index 31dc8d8e177..055a38a76e3 100644
--- a/lisp/net/newst-backend.el
+++ b/lisp/net/newst-backend.el
@@ -1676,15 +1676,6 @@ Sat, 07 Sep 2002 00:00:01 GMT
              nil))))
     nil))
 
-;; FIXME: Can this be replaced by seq-intersection?
-(defun newsticker--lists-intersect-p (list1 list2)
-  "Return t if LIST1 and LIST2 share elements."
-  (let ((result nil))
-    (dolist (elt list1)
-      (if (memq elt list2)
-          (setq result t)))
-    result))
-
 (defun newsticker--update-process-ids ()
   "Update list of ids of active newsticker processes.
 Checks list of active processes against list of newsticker processes."
diff --git a/lisp/net/newst-plainview.el b/lisp/net/newst-plainview.el
index 55fa19cbf2a..5c734aaeb2c 100644
--- a/lisp/net/newst-plainview.el
+++ b/lisp/net/newst-plainview.el
@@ -573,14 +573,10 @@ calls `w3m-toggle-inline-image'.  It works only if
                 (when pos
                   (goto-char pos)
                   (when (get-text-property pos 'w3m-image)
-                    (let ((invis (newsticker--lists-intersect-p
-                                  (get-text-property (1- (point))
-                                                     'invisible)
-                                  buffer-invisibility-spec)))
-                      (unless  (car (get-text-property (1- (point))
-                                                       'display))
-                        (unless invis
-                          (w3m-toggle-inline-image t)))))))))))))
+                    (unless (car (get-text-property (1- (point))
+                                                    'display))
+                      (unless (invisible-p (1- (point)))
+                        (w3m-toggle-inline-image t))))))))))))
 
 ;; ======================================================================
 ;;; Keymap stuff
@@ -606,9 +602,7 @@ is non-nil."
          (goto-char (point-min))
          (newsticker-next-new-item t))
        (setq go-ahead nil))
-      (unless (newsticker--lists-intersect-p
-               (get-text-property (point) 'invisible)
-               buffer-invisibility-spec)
+      (unless (invisible-p (point))
        ;; this item is invisible -- continue search
         (setq go-ahead nil))))
   (run-hooks 'newsticker-select-item-hook)
@@ -627,9 +621,7 @@ is non-nil."
        (unless do-not-wrap-at-bob
          (goto-char (point-max))
          (newsticker--buffer-goto '(item) 'new t)))
-      (unless (newsticker--lists-intersect-p
-               (get-text-property (point) 'invisible)
-                   buffer-invisibility-spec)
+      (unless (invisible-p (point))
        (setq go-ahead nil))))
   (run-hooks 'newsticker-select-item-hook)
   (point))
@@ -652,9 +644,7 @@ non-nil."
        (unless do-not-wrap-at-eob
          (goto-char (point-min)))
        (setq go-ahead nil))
-      (unless (newsticker--lists-intersect-p
-               (get-text-property (point) 'invisible)
-                   buffer-invisibility-spec)
+      (unless (invisible-p (point))
        (setq go-ahead nil))))
   (run-hooks 'newsticker-select-item-hook)
   (force-mode-line-update)
@@ -673,9 +663,7 @@ auto-narrow-to-item is enabled, nil is returned."
       (while go-ahead
         (unless (newsticker--buffer-goto '(item))
           (setq go-ahead nil))
-        (unless (newsticker--lists-intersect-p
-                 (get-text-property (point) 'invisible)
-                 buffer-invisibility-spec)
+        (unless (invisible-p (point))
           (setq go-ahead nil)))
       (if (and (> (point) current-pos)
                (< (point) end-of-feed))
@@ -700,9 +688,7 @@ is non-nil."
        (goto-char (point-max))))
     (while go-ahead
       (if (newsticker--buffer-goto search-list nil t)
-          (unless (newsticker--lists-intersect-p
-                   (get-text-property (point) 'invisible)
-                   buffer-invisibility-spec)
+          (unless (invisible-p (point))
             (setq go-ahead nil))
         (goto-char (point-min))
         (setq go-ahead nil))))
@@ -1079,9 +1065,7 @@ If VALUE is nil, auto-narrowing is turned off, otherwise 
it is turned on."
       (while (< (point) (point-max))
         (unless (newsticker--buffer-goto '(item))
           (throw 'result nil))
-        (unless (newsticker--lists-intersect-p
-                 (get-text-property (point) 'invisible)
-                 buffer-invisibility-spec)
+        (unless (invisible-p (point))
           (throw 'result t))))))
 
 (defun newsticker-previous-item-available-p ()
@@ -1091,9 +1075,7 @@ If VALUE is nil, auto-narrowing is turned off, otherwise 
it is turned on."
       (while (> (point) (point-min))
         (unless (newsticker--buffer-goto '(item) nil t)
           (throw 'result nil))
-        (unless (newsticker--lists-intersect-p
-                 (get-text-property (point) 'invisible)
-                 buffer-invisibility-spec)
+        (unless (invisible-p (point))
           (throw 'result t))))))
 
 (defun newsticker-item-not-old-p ()
diff --git a/lisp/net/tramp-container.el b/lisp/net/tramp-container.el
index 7f8d4473ad7..2e9ddc64bd3 100644
--- a/lisp/net/tramp-container.el
+++ b/lisp/net/tramp-container.el
@@ -158,26 +158,40 @@ If it is nil, the default context will be used."
   "Tramp method name to use to connect to Flatpak sandboxes.")
 
 ;;;###tramp-autoload
-(defun tramp-container--completion-function (program)
+(defun tramp-container--completion-function (method)
   "List running containers available for connection.
-PROGRAM is the program to be run for \"ps\", either
-`tramp-docker-program' or `tramp-podman-program'.
+METHOD is the Tramp method to be used for \"ps\", either
+`tramp-docker-method' or `tramp-podman-method'.
 
 This function is used by `tramp-set-completion-function', please
 see its function help for a description of the format."
-  (when-let ((default-directory tramp-compat-temporary-file-directory)
-            (raw-list (shell-command-to-string
-                       (concat program " ps --format '{{.ID}}\t{{.Names}}'")))
-             (lines (split-string raw-list "\n" 'omit))
-             (names (mapcar
-                    (lambda (line)
-                       (when (string-match
-                             (rx bol (group (1+ nonl))
-                                 "\t" (? (group (1+ nonl))) eol)
-                             line)
-                        (or (match-string 2 line) (match-string 1 line))))
-                     lines)))
-    (mapcar (lambda (name) (list nil name)) (delq nil names))))
+  (let ((default-directory
+        (or (and (member method tramp-completion-multi-hop-methods)
+                 tramp--last-hop-directory)
+            tramp-compat-temporary-file-directory))
+       (program (tramp-get-method-parameter
+                 (make-tramp-file-name :method method) 'tramp-login-program))
+       non-essential)
+    ;; We don't use connection properties, because this information
+    ;; shouldn't be kept persistently.
+    (with-tramp-file-property
+       (when (tramp-tramp-file-p default-directory)
+         (tramp-dissect-file-name default-directory))
+       (concat "/" method ":") "user-host-completions"
+      (when-let ((raw-list
+                 (shell-command-to-string
+                  (concat program " ps --format '{{.ID}}\t{{.Names}}'")))
+                (lines (split-string raw-list "\n" 'omit))
+                (names
+                 (mapcar
+                  (lambda (line)
+                    (when (string-match
+                           (rx bol (group (1+ nonl))
+                               "\t" (? (group (1+ nonl))) eol)
+                           line)
+                      (or (match-string 2 line) (match-string 1 line))))
+                  lines)))
+       (mapcar (lambda (name) (list nil name)) (delq nil names))))))
 
 ;;;###tramp-autoload
 (defun tramp-kubernetes--completion-function (&rest _args)
@@ -382,13 +396,11 @@ see its function help for a description of the format."
 
  (tramp-set-completion-function
   tramp-docker-method
-  `((tramp-container--completion-function
-     ,(executable-find tramp-docker-program))))
+  `((tramp-container--completion-function ,tramp-docker-method)))
 
  (tramp-set-completion-function
   tramp-podman-method
-  `((tramp-container--completion-function
-     ,(executable-find tramp-podman-program))))
+  `((tramp-container--completion-function ,tramp-podman-method)))
 
  (tramp-set-completion-function
   tramp-kubernetes-method
@@ -402,6 +414,9 @@ see its function help for a description of the format."
   tramp-flatpak-method
   '((tramp-flatpak--completion-function "")))
 
+ (add-to-list 'tramp-completion-multi-hop-methods tramp-docker-method)
+ (add-to-list 'tramp-completion-multi-hop-methods tramp-podman-method)
+
  ;; Default connection-local variables for Tramp.
 
  (defconst tramp-kubernetes-connection-local-default-variables
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 0599f89655c..c00234d43da 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -2831,7 +2831,8 @@ the result will be a local, non-Tramp, file name."
     (with-parsed-tramp-file-name name nil
       ;; If connection is not established yet, run the real handler.
       (if (not (tramp-connectable-p v))
-         (tramp-run-real-handler #'expand-file-name (list name))
+         (tramp-drop-volume-letter
+          (tramp-run-real-handler #'expand-file-name (list name)))
        (unless (tramp-run-real-handler #'file-name-absolute-p (list localname))
          (setq localname (concat "~/" localname)))
        ;; Tilde expansion if necessary.  This needs a shell which
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 05d28e8494f..9ec3f9cb397 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -2720,6 +2720,9 @@ not in completion mode."
 
       (tramp-run-real-handler #'file-exists-p (list filename))))
 
+(defvar tramp--last-hop-directory nil
+  "Tracks the directory from which to run login programs.")
+
 ;; Method, host name and user name completion.
 ;; `tramp-completion-dissect-file-name' returns a list of
 ;; `tramp-file-name' structures.  For all of them we return possible
@@ -2728,16 +2731,8 @@ not in completion mode."
   "Like `file-name-all-completions' for partial Tramp files."
   (let ((fullname
         (tramp-drop-volume-letter (expand-file-name filename directory)))
-       ;; When `tramp-syntax' is `simplified', we need a default method.
-       (tramp-default-method
-        (and (string-empty-p tramp-postfix-method-format)
-             tramp-default-method))
-       (tramp-default-method-alist
-        (and (string-empty-p tramp-postfix-method-format)
-             tramp-default-method-alist))
-       tramp-default-user tramp-default-user-alist
-       tramp-default-host tramp-default-host-alist
-       hop result result1)
+       (directory (tramp-drop-volume-letter directory))
+       tramp--last-hop-directory hop result result1)
 
     ;; Suppress hop from completion.
     (when (string-match
@@ -2747,56 +2742,68 @@ not in completion mode."
                      (regexp tramp-postfix-hop-regexp))))
           fullname)
       (setq hop (match-string 1 fullname)
-           fullname (replace-match "" nil nil fullname 1)))
-
-    ;; Possible completion structures.
-    (dolist (elt (tramp-completion-dissect-file-name fullname))
-      (let* ((method (tramp-file-name-method elt))
-            (user (tramp-file-name-user elt))
-            (host (tramp-file-name-host elt))
-            (localname (tramp-file-name-localname elt))
-            (m (tramp-find-method method user host))
-            all-user-hosts)
-
-       (unless localname ;; Nothing to complete.
-
-         (if (or user host)
-
-             ;; Method dependent user / host combinations.
-             (progn
-               (mapc
-                (lambda (x)
-                  (setq all-user-hosts
-                        (append all-user-hosts
-                                (funcall (nth 0 x) (nth 1 x)))))
-                (tramp-get-completion-function m))
-
-               (setq result
-                     (append result
-                             (mapcar
-                              (lambda (x)
-                                (tramp-get-completion-user-host
-                                 method user host (nth 0 x) (nth 1 x)))
-                              (delq nil all-user-hosts)))))
-
-           ;; Possible methods.
-           (setq result
-                 (append result (tramp-get-completion-methods m hop)))))))
-
-    ;; Unify list, add hop, remove nil elements.
-    (dolist (elt result)
-      (when elt
-       (setq elt (replace-regexp-in-string
-                  tramp-prefix-regexp (concat tramp-prefix-format hop) elt))
-       (push (substring elt (length directory)) result1)))
-
-    ;; Complete local parts.
-    (delete-dups
-     (append
-      result1
-      (ignore-errors
-        (tramp-run-real-handler
-        #'file-name-all-completions (list filename directory)))))))
+           fullname (replace-match "" nil nil fullname 1)
+           tramp--last-hop-directory
+           (tramp-make-tramp-file-name (tramp-dissect-hop-name hop))))
+
+    (let (;; When `tramp-syntax' is `simplified', we need a default method.
+         (tramp-default-method
+          (and (string-empty-p tramp-postfix-method-format)
+               tramp-default-method))
+         (tramp-default-method-alist
+          (and (string-empty-p tramp-postfix-method-format)
+               tramp-default-method-alist))
+         tramp-default-user tramp-default-user-alist
+         tramp-default-host tramp-default-host-alist)
+
+      ;; Possible completion structures.
+      (dolist (elt (tramp-completion-dissect-file-name fullname))
+       (let* ((method (tramp-file-name-method elt))
+              (user (tramp-file-name-user elt))
+              (host (tramp-file-name-host elt))
+              (localname (tramp-file-name-localname elt))
+              (m (tramp-find-method method user host))
+              all-user-hosts)
+
+         (unless localname ;; Nothing to complete.
+
+           (if (or user host)
+
+               ;; Method dependent user / host combinations.
+               (progn
+                 (mapc
+                  (lambda (x)
+                    (setq all-user-hosts
+                          (append all-user-hosts
+                                  (funcall (nth 0 x) (nth 1 x)))))
+                  (tramp-get-completion-function m))
+
+                 (setq result
+                       (append result
+                               (mapcar
+                                (lambda (x)
+                                  (tramp-get-completion-user-host
+                                   method user host (nth 0 x) (nth 1 x)))
+                                (delq nil all-user-hosts)))))
+
+             ;; Possible methods.
+             (setq result
+                   (append result (tramp-get-completion-methods m hop)))))))
+
+      ;; Unify list, add hop, remove nil elements.
+      (dolist (elt result)
+        (when elt
+         (setq elt (replace-regexp-in-string
+                    tramp-prefix-regexp (concat tramp-prefix-format hop) elt))
+         (push (substring elt (length directory)) result1)))
+
+      ;; Complete local parts.
+      (delete-dups
+       (append
+        result1
+        (ignore-errors
+          (tramp-run-real-handler
+          #'file-name-all-completions (list filename directory))))))))
 
 ;; Method, host name and user name completion for a file.
 (defun tramp-completion-handle-file-name-completion
@@ -2916,13 +2923,13 @@ remote host and localname (filename on remote host)."
 
 ;; This function returns all possible method completions, adding the
 ;; trailing method delimiter.
-(defun tramp-get-completion-methods (partial-method hop)
+(defun tramp-get-completion-methods (partial-method &optional multi-hop)
   "Return all method completions for PARTIAL-METHOD.
-If HOP is non-nil, return only multi-hop capable methods."
+If MULTI-HOP is non-nil, return only multi-hop capable methods."
   (mapcar
    (lambda (method)
      (and method (string-prefix-p (or partial-method "") method)
-         (or (not hop)
+         (or (not multi-hop)
              (tramp-multi-hop-p (make-tramp-file-name :method method)))
          (tramp-completion-make-tramp-file-name method nil nil nil)))
    (mapcar #'car tramp-methods)))
@@ -3002,6 +3009,12 @@ This function is added always in 
`tramp-get-completion-function'
 for all methods.  Resulting data are derived from default settings."
   `((,(tramp-find-user method nil nil) ,(tramp-find-host method nil nil))))
 
+;;;###tramp-autoload
+(defcustom tramp-completion-multi-hop-methods nil
+  "Methods for which to provide completions over multi-hop connections."
+  :version "30.1"
+  :type '(repeat (string :tag "Method name")))
+
 (defcustom tramp-completion-use-auth-sources auth-source-do-cache
   "Whether to use `auth-source-search' for completion of user and host names.
 This could be disturbing, if it requires a password / passphrase,
@@ -4573,8 +4586,9 @@ Do not set it manually, it is used buffer-local in 
`tramp-get-lock-pid'.")
 
 (defun tramp-multi-hop-p (vec)
   "Whether the method of VEC is capable of multi-hops."
-  (and (tramp-sh-file-name-handler-p vec)
-       (not (tramp-get-method-parameter vec 'tramp-copy-program))))
+  (let ((tramp-verbose 0))
+    (and (tramp-sh-file-name-handler-p vec)
+        (not (tramp-get-method-parameter vec 'tramp-copy-program)))))
 
 (defun tramp-add-hops (vec)
   "Add ad-hoc proxy definitions to `tramp-default-proxies-alist'."
@@ -5602,7 +5616,8 @@ If the user quits via `C-g', it is propagated up to 
`tramp-file-name-handler'."
             (v (process-get proc 'tramp-vector)))
     (dolist (p (delq proc (process-list)))
       (when (tramp-file-name-equal-p v (process-get p 'tramp-vector))
-       (with-local-quit (accept-process-output p 0 nil t)))))
+       (with-tramp-suspended-timers
+         (with-local-quit (accept-process-output p 0 nil t))))))
 
   (with-current-buffer (process-buffer proc)
     (let ((inhibit-read-only t)
diff --git a/lisp/obsolete/url-ns.el b/lisp/obsolete/url-ns.el
index 20318867634..53db684887c 100644
--- a/lisp/obsolete/url-ns.el
+++ b/lisp/obsolete/url-ns.el
@@ -39,13 +39,14 @@
 
 ;;;###autoload
 (defun dnsResolve (host)
-  (url-gateway-nslookup-host host))
+  (with-suppressed-warnings ((obsolete url-gateway-nslookup-host))
+    (url-gateway-nslookup-host host)))
 
 ;;;###autoload
 (defun isResolvable (host)
   (if (string-match "^[0-9.]+$" host)
       t
-    (not (string= host (url-gateway-nslookup-host host)))))
+    (not (string= host (dnsResolve host)))))
 
 ;;;###autoload
 (defun isInNet (ip net mask)
diff --git a/lisp/org/oc-basic.el b/lisp/org/oc-basic.el
index 1c8c37aa941..5c9aad8f6a5 100644
--- a/lisp/org/oc-basic.el
+++ b/lisp/org/oc-basic.el
@@ -162,7 +162,7 @@ Return a hash table with citation references as keys and 
fields alist as values.
         (puthash (cdr (assq 'id item))
                  (mapcar (pcase-lambda (`(,field . ,value))
                            (pcase field
-                             ((or 'author 'editors)
+                             ((or 'author 'editor)
                               ;; Author and editors are arrays of
                               ;; objects, each of them designing a
                               ;; person.  These objects may contain
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index 296468eed1a..0debd1a6818 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -6705,20 +6705,8 @@ The function returns the new value of 
`org-element--cache-change-warning'."
        (setq org-element--cache-change-tic (buffer-chars-modified-tick))
        (setq org-element--cache-last-buffer-size (buffer-size))
        (goto-char beg)
-       (beginning-of-line)
-       (let ((bottom (save-excursion
-                       (goto-char end)
-                       (if (and (bolp)
-                                ;; When beg == end, still extent to eol.
-                                (> (point) beg))
-                           ;; FIXME: Potential pitfall.
-                           ;; We are appending to an element end.
-                           ;; Unless the last inserted char is not
-                           ;; newline, the next element is not broken
-                           ;; and does not need to be purged from the
-                           ;; cache.
-                           end
-                         (line-end-position)))))
+       (forward-line 0)
+       (let ((bottom (save-excursion (goto-char end) (line-end-position))))
          (prog1
              ;; Use the worst change warning to not miss important edits.
              ;; This function is called before edit and after edit by
@@ -7859,7 +7847,7 @@ element ending there."
     (setq cached-only nil))
   (let (element)
     (when (org-element--cache-active-p)
-      (if (not org-element--cache) (org-element-cache-reset)
+      (if (not (org-with-base-buffer nil org-element--cache)) 
(org-element-cache-reset)
         (unless cached-only (org-element--cache-sync (current-buffer) pom))))
     (setq element (if cached-only
                       (when (and (org-element--cache-active-p)
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el
index 57e406b24fc..3b58ea06818 100644
--- a/lisp/org/org-version.el
+++ b/lisp/org/org-version.el
@@ -5,13 +5,13 @@
 (defun org-release ()
   "The release version of Org.
 Inserted by installing Org mode or when a release is made."
-   (let ((org-release "9.6.7"))
+   (let ((org-release "9.6.8"))
      org-release))
 ;;;###autoload
 (defun org-git-version ()
   "The Git version of Org mode.
 Inserted by installing Org or when a release is made."
-   (let ((org-git-version "release_9.6.7-13-g99cc96"))
+   (let ((org-git-version "release_9.6.8-3-g21171d"))
      org-git-version))
 
 (provide 'org-version)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index f56aa4f6f69..2c15a37e9c1 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -9,7 +9,7 @@
 ;; URL: https://orgmode.org
 ;; Package-Requires: ((emacs "26.1"))
 
-;; Version: 9.6.7
+;; Version: 9.6.8
 
 ;; This file is part of GNU Emacs.
 ;;
@@ -6322,7 +6322,10 @@ unconditionally."
        (if (not level) (outline-next-heading) ;before first headline
         (org-back-to-heading invisible-ok)
         (when (equal arg '(16)) (org-up-heading-safe))
-        (org-end-of-subtree)))
+        (org-end-of-subtree invisible-ok 'to-heading)))
+      ;; At `point-max', if the file does not have ending newline,
+      ;; create one, so that we are not appending stars at non-empty
+      ;; line.
       (unless (bolp) (insert "\n"))
       (when (and blank? (save-excursion
                           (backward-char)
@@ -6334,7 +6337,9 @@ unconditionally."
         (backward-char))
       (unless (and blank? (org-previous-line-empty-p))
        (org-N-empty-lines-before-current (if blank? 1 0)))
-      (insert stars " ")
+      (insert stars " " "\n")
+      ;; Move point after stars.
+      (backward-char)
       ;; When INVISIBLE-OK is non-nil, ensure newly created headline
       ;; is visible.
       (unless invisible-ok
@@ -14753,12 +14758,12 @@ is considered `day' (i.e. only `bracket', `day', and 
`after' return
 values are possible).
 
 When matching, the match groups are the following:
-  group 1: year, if any
-  group 2: month, if any
-  group 3: day number, if any
-  group 4: day name, if any
-  group 5: hours, if any
-  group 6: minutes, if any"
+  group 2: year, if any
+  group 3: month, if any
+  group 4: day number, if any
+  group 5: day name, if any
+  group 7: hours, if any
+  group 8: minutes, if any"
   (let* ((regexp
           (if extended
               (if (eq extended 'agenda)
@@ -17662,6 +17667,8 @@ If INDENT is non-nil, call `newline-and-indent' with 
ARG to
 indent unconditionally; otherwise, call `newline' with ARG and
 INTERACTIVE, which can trigger indentation if
 `electric-indent-mode' is enabled."
+  (when interactive
+    (org-fold-check-before-invisible-edit 'insert))
   (if indent
       (org-newline-and-indent arg)
     (newline arg interactive)))
diff --git a/lisp/plstore.el b/lisp/plstore.el
index d18d461d7d1..7dc991aeec7 100644
--- a/lisp/plstore.el
+++ b/lisp/plstore.el
@@ -24,14 +24,31 @@
 
 ;; Plist based data store providing search and partial encryption.
 ;;
-;; By default, this package uses symmetric encryption, which means
+;; By default, this library uses symmetric encryption, which means
 ;; that you have to enter the password protecting your store more
 ;; often than you probably expect to.  To use public key encryption
-;; with this package, create a GnuPG key and customize user option
+;; with this library, create a GnuPG key and customize user option
 ;; `plstore-encrypt-to' to use it.  You can then configure the GnuPG
 ;; agent to adjust caching and expiration of the passphrase for your
 ;; store.
 ;;
+;; You can read more on these topics in the EasyPG Assistant user's
+;; manual (Info node `(epa)'), of which much information also applies
+;; to this library.  Most notably:
+;;
+;; - Info node `(epa)GnuPG version compatibility'
+;; - Info node `(epa)GnuPG Pinentry'
+;; - Info node `(epa)Caching Passphrases'
+;;
+;; Use only keyword symbols (starting with a colon) as property names
+;; in any plist stored with this library.  While this library does not
+;; actively enforce the use of keyword symbols, it silently assumes
+;; that the first character of all property names can be discarded
+;; without sacrificing uniqueness of names (FIXME).  Likewise, this
+;; library does not enforce that the plists provided as input are
+;; actually valid and can behave in undefined ways if they are not
+;; (FIXME).
+;;
 ;; Creating:
 ;;
 ;; ;; Open a new store associated with ~/.emacs.d/auth.plist.
@@ -52,8 +69,8 @@
 ;; (plstore-close store)
 ;;
 ;; Avoid marking one property both as public *and* secret, as the
-;; behavior of this package with respect to such duplicate properties
-;; is not (yet) defined.
+;; behavior of this library with respect to such duplicate properties
+;; is not defined (FIXME).
 ;;
 ;; Searching:
 ;;
@@ -71,7 +88,7 @@
 ;; ;; While the entry "baz" associated with "baz.example.org" has also
 ;; ;; a secret property `:password', it is encrypted together with
 ;; ;; `:user' of "bar", so no need to decrypt the secret.
-;; (plstore-find store '(:host ("bar.example.org")))
+;; (plstore-find store '(:host ("baz.example.org")))
 ;;
 ;; (plstore-close store)
 ;;
@@ -87,8 +104,8 @@
 ;; `:secret-' prefix) is marked as secret.  Thus, when you save the
 ;; buffer, the `:secret-user' property is encrypted as `:user'.  Do
 ;; not use a property consisting solely of the prefix, as the behavior
-;; of this package with respect to such properties is not (yet)
-;; defined.
+;; of this library with respect to such properties is not defined
+;; (FIXME).
 ;;
 ;; You can toggle the view between encrypted form and the decrypted
 ;; form with C-c C-c.
@@ -101,7 +118,7 @@
 ;; Internals:
 ;;
 ;; This is information on the internal data structure and functions of
-;; this package.  None of it should be necessary to actually use it.
+;; this library.  None of it should be necessary to actually use it.
 ;; For easier reading, we usually do not distinguish in this internal
 ;; documentation between a Lisp object and its printed representation.
 ;;
@@ -589,7 +606,11 @@ If no one is selected, symmetric encryption will be 
performed.  "
        (insert ";;; secret entries\n" (pp-to-string cipher)))))
 
 (defun plstore-save (plstore)
-  "Save PLSTORE to its associated file."
+  "Save PLSTORE to its associated file.
+Save with symmetric encryption or public key encryption depending
+on `plstore-encrypt-to'.  If `plstore-encrypt-to' is non-nil but
+none of the recipients from `plstore-encrypt-to' matches any
+GnuPG key, silently save with symmetric encryption." ; (FIXME)
   (with-current-buffer (plstore--get-buffer plstore)
     (erase-buffer)
     (plstore--insert-buffer plstore)
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index b3c48eb2c65..165bdd668c3 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -1127,34 +1127,36 @@ BEG and END are described in `treesit-range-rules'."
   (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
   (setq-local treesit-defun-name-function #'c-ts-mode--defun-name)
 
-  (setq-local treesit-sentence-type-regexp
-              ;; compound_statement makes us jump over too big units
-              ;; of code, so skip that one, and include the other
-              ;; statements.
-              (regexp-opt '("preproc"
-                            "declaration"
-                            "specifier"
-                            "attributed_statement"
-                            "labeled_statement"
-                            "expression_statement"
-                            "if_statement"
-                            "switch_statement"
-                            "do_statement"
-                            "while_statement"
-                            "for_statement"
-                            "return_statement"
-                            "break_statement"
-                            "continue_statement"
-                            "goto_statement"
-                            "case_statement")))
-
   ;; IMO it makes more sense to define what's NOT sexp, since sexp by
   ;; spirit, especially when used for movement, is like "expression"
   ;; or "syntax unit". --yuan
-  (setq-local treesit-sexp-type-regexp
-              ;; It more useful to include semicolons as sexp so that
-              ;; users can move to the end of a statement.
-              (rx (not (or "{" "}" "[" "]" "(" ")" ","))))
+  (setq-local treesit-thing-settings
+              `((c
+                 ;; It's more useful to include semicolons as sexp so
+                 ;; that users can move to the end of a statement.
+                 (sexp (not ,(rx (or "{" "}" "[" "]" "(" ")" ","))))
+                 ;; compound_statement makes us jump over too big units
+                 ;; of code, so skip that one, and include the other
+                 ;; statements.
+                 (sentence
+                  ,(regexp-opt '("preproc"
+                                 "declaration"
+                                 "specifier"
+                                 "attributed_statement"
+                                 "labeled_statement"
+                                 "expression_statement"
+                                 "if_statement"
+                                 "switch_statement"
+                                 "do_statement"
+                                 "while_statement"
+                                 "for_statement"
+                                 "return_statement"
+                                 "break_statement"
+                                 "continue_statement"
+                                 "goto_statement"
+                                 "case_statement")))
+                 (text ,(regexp-opt '("comment"
+                                      "raw_string_literal"))))))
 
   ;; Nodes like struct/enum/union_specifier can appear in
   ;; function_definitions, so we need to find the top-level node.
@@ -1291,9 +1293,6 @@ recommended to enable `electric-pair-mode' with this 
mode."
   :after-hook (c-ts-mode-set-modeline)
 
   (when (treesit-ready-p 'cpp)
-    (setq-local treesit-text-type-regexp
-                (regexp-opt '("comment"
-                              "raw_string_literal")))
 
     (treesit-parser-create 'cpp)
 
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 37bb84ab5ba..866c802ca43 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -959,10 +959,12 @@ Key bindings:
   ;; Comments.
   (c-ts-common-comment-setup)
 
-  (setq-local treesit-text-type-regexp
-              (regexp-opt '("comment"
-                            "verbatim_string-literal"
-                            "interpolated_verbatim_string-text")))
+  (setq-local treesit-thing-settings
+              `((c-sharp
+                 (text
+                  ,(regexp-opt '("comment"
+                                 "verbatim_string-literal"
+                                 "interpolated_verbatim_string-text"))))))
 
   ;; Indent.
   (setq-local treesit-simple-indent-rules csharp-ts-mode--indent-rules)
diff --git a/lisp/progmodes/dockerfile-ts-mode.el 
b/lisp/progmodes/dockerfile-ts-mode.el
index 333158e20f6..0305bea5182 100644
--- a/lisp/progmodes/dockerfile-ts-mode.el
+++ b/lisp/progmodes/dockerfile-ts-mode.el
@@ -175,8 +175,9 @@ the subtrees."
                 dockerfile-ts-mode--indent-rules)
 
     ;; Navigation
-    (setq-local treesit-sentence-type-regexp
-                "instruction")
+    (setq-local treesit-thing-settings
+                `((dockerfile
+                   (sentence "instruction"))))
 
     ;; Font-lock.
     (setq-local treesit-font-lock-settings
diff --git a/lisp/progmodes/ebnf2ps.el b/lisp/progmodes/ebnf2ps.el
index 3e83d288408..819f39cb4e5 100644
--- a/lisp/progmodes/ebnf2ps.el
+++ b/lisp/progmodes/ebnf2ps.el
@@ -5247,7 +5247,7 @@ killed after process termination."
        (or ebnf-fonts-required
           (setq ebnf-fonts-required
                 (mapconcat #'identity
-                           (ps-remove-duplicates
+                           (delete-dups
                             (mapcar #'ebnf-font-name-select
                                     (list ebnf-production-font
                                           ebnf-terminal-font
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index 65daa0941d5..2bc5351145d 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -108,6 +108,8 @@
 (require 'filenotify)
 (require 'ert)
 (require 'text-property-search nil t)
+(require 'diff-mode)
+(require 'diff)
 
 ;; These dependencies are also GNU ELPA core packages.  Because of
 ;; bug#62576, since there is a risk that M-x package-install, despite
@@ -257,7 +259,8 @@ chosen (interactively or automatically)."
                                  . ,(eglot-alternatives
                                      '(("marksman" "server")
                                        ("vscode-markdown-language-server" 
"--stdio"))))
-                                (graphviz-dot-mode . ("dot-language-server" 
"--stdio")))
+                                (graphviz-dot-mode . ("dot-language-server" 
"--stdio"))
+                                (terraform-mode . ("terraform-ls" "serve")))
   "How the command `eglot' guesses the server to start.
 An association list of (MAJOR-MODE . CONTACT) pairs.  MAJOR-MODE
 identifies the buffers that are to be managed by a specific
@@ -388,10 +391,39 @@ done by `eglot-reconnect'."
   :type '(choice (const :tag "No limit" nil)
                  (integer :tag "Number of characters")))
 
-(defcustom eglot-confirm-server-initiated-edits 'confirm
-  "Non-nil if server-initiated edits should be confirmed with user."
-  :type '(choice (const :tag "Don't show confirmation prompt" nil)
-                 (const :tag "Show confirmation prompt" confirm)))
+(define-obsolete-variable-alias 'eglot-confirm-server-initiated-edits
+  'eglot-confirm-server-edits "1.16")
+
+(defcustom eglot-confirm-server-edits '((eglot-rename . nil)
+                                        (t . maybe-summary))
+  "Control if changes proposed by LSP should be confirmed with user.
+
+If this variable's value is the symbol `diff', a diff buffer is
+pops up, allowing the user to apply each change individually.  If
+the symbol `summary' or any other non-nil value, the user is
+prompted in the minibuffer with aa short summary of changes.  The
+symbols `maybe-diff' and `maybe-summary' mean that the
+confirmation is offered to the user only if the changes target
+files visited in buffers.  Finally, a nil value means all changes
+are applied directly without any confirmation.
+
+If this variable's value can also be an alist ((COMMAND . ACTION)
+...) where COMMAND is a symbol designating a command, such as
+`eglot-rename', `eglot-code-actions',
+`eglot-code-action-quickfix', etc.  ACTION is one of the symbols
+described above.  The value `t' for COMMAND is accepted and its
+ACTION is the default value for commands not in the alist."
+  :type (let ((basic-choices
+               '((const :tag "Use diff" diff)
+                 (const :tag "Summarize and prompt" summary)
+                 (const :tag "Maybe use diff" maybe-diff)
+                 (const :tag "Maybe summarize and prompt" maybe-summary)
+                 (const :tag "Don't confirm" nil))))
+          `(choice ,@basic-choices
+                   (alist :tag "Per-command alist"
+                          :key-type (choice (function :tag "Command")
+                                            (const :tag "Default" t))
+                          :value-type (choice . ,basic-choices)))))
 
 (defcustom eglot-extend-to-xref nil
   "If non-nil, activate Eglot in cross-referenced non-project files."
@@ -753,7 +785,7 @@ ACTION is an LSP object of either `CodeAction' or `Command' 
type."
       (if (and (null edit) (null command) data
                (eglot--server-capable :codeActionProvider :resolveProvider))
           (eglot-execute server (eglot--request server :codeAction/resolve 
action))
-        (when edit (eglot--apply-workspace-edit edit))
+        (when edit (eglot--apply-workspace-edit edit this-command))
         (when command (eglot--request server :workspace/executeCommand 
command)))))))
 
 (cl-defgeneric eglot-initialization-options (server)
@@ -2379,7 +2411,7 @@ THINGS are either registrations or unregisterations 
(sic)."
 (cl-defmethod eglot-handle-request
   (_server (_method (eql workspace/applyEdit)) &key _label edit)
   "Handle server request workspace/applyEdit."
-  (eglot--apply-workspace-edit edit eglot-confirm-server-initiated-edits)
+  (eglot--apply-workspace-edit edit last-command)
   `(:applied t))
 
 (cl-defmethod eglot-handle-request
@@ -2608,8 +2640,10 @@ local value of the `eglot-workspace-configuration' 
variable, else
 use the root of SERVER's `eglot--project'."
   (let ((val (with-temp-buffer
                (setq default-directory
-                     (if path
-                         (file-name-directory path)
+                     ;; See github#1281
+                     (if path (if (file-directory-p path)
+                                  (file-name-as-directory path)
+                                (file-name-directory path))
                        (project-root (eglot--project server))))
                ;; Set the major mode to be the first of the managed
                ;; modes.  This is the one the user started eglot in.
@@ -3429,8 +3463,59 @@ If SILENT, don't echo progress in mode-line."
       (when reporter
         (progress-reporter-done reporter)))))
 
-(defun eglot--apply-workspace-edit (wedit &optional confirm)
-  "Apply the workspace edit WEDIT.  If CONFIRM, ask user first."
+(defun eglot--confirm-server-edits (origin _prepared)
+  "Helper for `eglot--apply-workspace-edit.
+ORIGIN is a symbol designating a command.  Reads the
+`eglot-confirm-server-edits' user option and returns a symbol
+like `diff', `summary' or nil."
+  (let (v)
+    (cond ((symbolp eglot-confirm-server-edits) eglot-confirm-server-edits)
+          ((setq v (assoc origin eglot-confirm-server-edits)) (cdr v))
+          ((setq v (assoc t eglot-confirm-server-edits)) (cdr v)))))
+
+(defun eglot--propose-changes-as-diff (prepared)
+  "Helper for `eglot--apply-workspace-edit'.
+Goal is to popup a `diff-mode' buffer containing all the changes
+of PREPARED, ready to apply with C-c C-a.  PREPARED is a
+list ((FILENAME EDITS VERSION)...)."
+  (with-current-buffer (get-buffer-create "*EGLOT proposed server changes*")
+    (buffer-disable-undo (current-buffer))
+    (let ((inhibit-read-only t)
+          (target (current-buffer)))
+      (diff-mode)
+      (erase-buffer)
+      (pcase-dolist (`(,path ,edits ,_) prepared)
+        (with-temp-buffer
+          (let* ((diff (current-buffer))
+                 (existing-buf (find-buffer-visiting path))
+                 (existing-buf-label (prin1-to-string existing-buf)))
+            (with-temp-buffer
+              (if existing-buf
+                  (insert-buffer-substring existing-buf)
+                (insert-file-contents path))
+              (eglot--apply-text-edits edits nil t)
+              (diff-no-select (or existing-buf path) (current-buffer) nil t 
diff)
+              (when existing-buf
+                ;; Here we have to pretend the label of the unsaved
+                ;; buffer is the actual file, just so that we can
+                ;; diff-apply without troubles.  If there's a better
+                ;; way, it probably involves changes to `diff.el'.
+                (with-current-buffer diff
+                  (goto-char (point-min))
+                  (while (search-forward existing-buf-label nil t)
+                    (replace-match (buffer-file-name existing-buf))))))
+            (with-current-buffer target
+              (insert-buffer-substring diff))))))
+    (setq-local buffer-read-only t)
+    (buffer-enable-undo (current-buffer))
+    (goto-char (point-min))
+    (pop-to-buffer (current-buffer))
+    (font-lock-ensure)))
+
+(defun eglot--apply-workspace-edit (wedit origin)
+  "Apply (or offer to apply) the workspace edit WEDIT.
+ORIGIN is a symbol designating the command that originated this
+edit proposed by the server."
   (eglot--dbind ((WorkspaceEdit) changes documentChanges) wedit
     (let ((prepared
            (mapcar (eglot--lambda ((TextDocumentEdit) textDocument edits)
@@ -3444,18 +3529,34 @@ If SILENT, don't echo progress in mode-line."
         ;; prefer documentChanges over changes.
         (cl-loop for (uri edits) on changes by #'cddr
                  do (push (list (eglot--uri-to-path uri) edits) prepared)))
-      (if (or confirm
-              (cl-notevery #'find-buffer-visiting
-                           (mapcar #'car prepared)))
-          (unless (y-or-n-p
-                   (format "[eglot] Server wants to edit:\n  %s\n Proceed? "
-                           (mapconcat #'identity (mapcar #'car prepared) "\n  
")))
-            (jsonrpc-error "User canceled server edit")))
-      (cl-loop for edit in prepared
-               for (path edits version) = edit
-               do (with-current-buffer (find-file-noselect path)
-                    (eglot--apply-text-edits edits version))
-               finally (eldoc) (eglot--message "Edit successful!")))))
+      (cl-flet ((notevery-visited-p ()
+                  (cl-notevery #'find-buffer-visiting
+                               (mapcar #'car prepared)))
+                (accept-p ()
+                  (y-or-n-p
+                   (format "[eglot] Server wants to edit:\n%sProceed? "
+                           (cl-loop
+                            for (f eds _) in prepared
+                            concat (format
+                                    "  %s (%d change%s)\n"
+                                    f (length eds)
+                                    (if (> (length eds) 1) "s" ""))))))
+                (apply ()
+                  (cl-loop for edit in prepared
+                   for (path edits version) = edit
+                   do (with-current-buffer (find-file-noselect path)
+                        (eglot--apply-text-edits edits version))
+                   finally (eldoc) (eglot--message "Edit successful!"))))
+        (let ((decision (eglot--confirm-server-edits origin prepared)))
+          (cond
+           ((or (eq decision 'diff)
+                (and (eq decision 'maybe-diff) (notevery-visited-p)))
+            (eglot--propose-changes-as-diff prepared))
+           ((or (memq decision '(t summary))
+                (and (eq decision 'maybe-summary) (notevery-visited-p)))
+            (when (accept-p) (apply)))
+           (t
+            (apply))))))))
 
 (defun eglot-rename (newname)
   "Rename the current symbol to NEWNAME."
@@ -3470,7 +3571,7 @@ If SILENT, don't echo progress in mode-line."
    (eglot--request (eglot--current-server-or-lose)
                    :textDocument/rename `(,@(eglot--TextDocumentPositionParams)
                                           :newName ,newname))
-   current-prefix-arg))
+   this-command))
 
 (defun eglot--region-bounds ()
   "Region bounds if active, else bounds of things at point."
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index a1091de43e9..42c1c715c73 100644
--- a/lisp/progmodes/gdb-mi.el
+++ b/lisp/progmodes/gdb-mi.el
@@ -222,7 +222,6 @@ address for root variables.")
 Only used for files that Emacs can't find.")
 (defvar gdb-active-process nil
   "GUD tooltips display variable values when t, and macro definitions 
otherwise.")
-(defvar gdb-error "Non-nil when GDB is reporting an error.")
 (defvar gdb-macro-info nil
   "Non-nil if GDB knows that the inferior includes preprocessor macro info.")
 (defvar gdb-register-names nil "List of register names.")
@@ -928,7 +927,7 @@ detailed description of this mode.
           (setq-local comint-input-ring-file-name hfile))
       (comint-read-input-ring t)))
   (gud-def gud-tbreak "tbreak %f:%l" "\C-t"
-          "Set temporary breakpoint at current line.")
+          "Set temporary breakpoint at current line." t)
   (gud-def gud-jump
           (progn (gud-call "tbreak %f:%l" arg) (gud-call "jump %f:%l"))
           "\C-j" "Set execution address to current line.")
@@ -959,7 +958,7 @@ detailed description of this mode.
           "Finish executing current function.")
   (gud-def gud-run    "-exec-run"
            nil
-           "Run the program.")
+           "Run the program." t)
 
   (gud-def gud-break (if (not (string-match "Disassembly" mode-name))
                         (gud-call "break %f:%l" arg)
@@ -967,7 +966,7 @@ detailed description of this mode.
                         (beginning-of-line)
                         (forward-char 2)
                         (gud-call "break *%a" arg)))
-          "\C-b" "Set breakpoint at current line or address.")
+          "\C-b" "Set breakpoint at current line or address." t)
 
   (gud-def gud-remove (if (not (string-match "Disassembly" mode-name))
                          (gud-call "clear %f:%l" arg)
@@ -975,7 +974,7 @@ detailed description of this mode.
                          (beginning-of-line)
                          (forward-char 2)
                          (gud-call "clear *%a" arg)))
-          "\C-d" "Remove breakpoint at current line or address.")
+          "\C-d" "Remove breakpoint at current line or address." t)
 
   ;; -exec-until doesn't support --all yet
   (gud-def gud-until  (if (not (string-match "Disassembly" mode-name))
@@ -1044,6 +1043,7 @@ detailed description of this mode.
 
   (setq gdb-first-prompt t)
   (setq gud-running nil)
+  (setq gud-async-running nil)
 
   (gdb-update)
 
@@ -2671,9 +2671,11 @@ Sets `gdb-thread-number' to new id."
   ;; Set `gdb-non-stop' when `gdb-last-command' is a CLI background
   ;; running command e.g. "run &", attach &" or a MI command
   ;; e.g. "-exec-run" or "-exec-attach".
-  (when (or (string-match "&\s*$" gdb-last-command)
-            (string-match "^-" gdb-last-command))
-    (gdb-try-check-target-async-support))
+  (if (or (string-match "&\s*$" gdb-last-command)
+          (string-match "^-" gdb-last-command))
+      (progn (gdb-try-check-target-async-support)
+             (setq gud-async-running t))
+    (setq gud-async-running nil))
 
   (gdb-force-mode-line-update
    (propertize gdb-inferior-status 'face font-lock-type-face))
diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el
index 09860a4cbde..3cc63aab84f 100644
--- a/lisp/progmodes/gud.el
+++ b/lisp/progmodes/gud.el
@@ -128,6 +128,10 @@ If SOFT is non-nil, returns nil if the symbol doesn't 
already exist."
   "Non-nil if debugged program is running.
 Used to gray out relevant toolbar icons.")
 
+(defvar gud-async-running nil
+  "Non-nil if debugged program is running in async mode.
+Check it when `gud-running' is t")
+
 (defvar gud-target-name "--unknown--"
   "The apparent name of the program being debugged in a gud buffer.")
 
@@ -261,13 +265,13 @@ Used to gray out relevant toolbar icons.")
      :visible (memq gud-minor-mode
                    '(gdbmi gdb guiler dbx xdb jdb pdb))]
     ["Set Breakpoint" gud-break
-     :enable (not gud-running)
+     :enable (or (not gud-running) gud-async-running)
      :visible (gud-tool-bar-item-visible-no-fringe)]
     ["Temporary Breakpoint" gud-tbreak
-     :enable (not gud-running)
+     :enable (or (not gud-running) gud-async-running)
      :visible (memq gud-minor-mode '(gdbmi gdb sdb xdb))]
     ["Remove Breakpoint" gud-remove
-     :enable (not gud-running)
+     :enable (or (not gud-running) gud-async-running)
      :visible (gud-tool-bar-item-visible-no-fringe)]
     ["Continue to selection" gud-until
      :enable (not gud-running)
@@ -283,7 +287,7 @@ Used to gray out relevant toolbar icons.")
      :visible (and (eq gud-minor-mode 'gdbmi)
                    (gdb-show-run-p))]
     ["Run" gud-run
-     :enable (not gud-running)
+     :enable (or (not gud-running) gud-async-running)
      :visible (or (memq gud-minor-mode '(gdb dbx jdb))
                  (and (eq gud-minor-mode 'gdbmi)
                       (or (not (gdb-show-run-p))
@@ -403,13 +407,15 @@ Uses `gud-<MINOR-MODE>-directories' to find the source 
files."
 ;; Of course you may use `gud-def' with any other debugger command, including
 ;; user defined ones.
 
-;; A macro call like (gud-def FUNC CMD KEY DOC) expands to a form
+;; A macro call like (gud-def FUNC CMD KEY DOC ASYNC-OK) expands to a form
 ;; which defines FUNC to send the command CMD to the debugger, gives
 ;; it the docstring DOC, and binds that function to KEY in the GUD
-;; major mode.  The function is also bound in the global keymap with the
+;; major mode. The FUNC still sends CMD when both ASYNC-OK and
+;; `gud-async-running' are t even `gud-running' is t.
+;; The function is also bound in the global keymap with the
 ;; GUD prefix.
 
-(defmacro gud-def (func cmd key &optional doc)
+(defmacro gud-def (func cmd key &optional doc async-ok)
   "Define FUNC to be a command sending CMD and bound to KEY, with
 optional doc string DOC.  Certain %-escapes in the string arguments
 are interpreted specially if present.  These are:
@@ -434,7 +440,7 @@ we're in the GUD buffer)."
      (defalias ',func (lambda (arg)
        ,@(if doc (list doc))
        (interactive "p")
-       (if (not gud-running)
+       (if (or (not gud-running) (and ,async-ok gud-async-running))
         ,(if (stringp cmd)
              `(gud-call ,cmd arg)
            ;; Unused lexical warning if cmd does not use "arg".
diff --git a/lisp/progmodes/heex-ts-mode.el b/lisp/progmodes/heex-ts-mode.el
index 68a537b9229..5237c767330 100644
--- a/lisp/progmodes/heex-ts-mode.el
+++ b/lisp/progmodes/heex-ts-mode.el
@@ -149,8 +149,9 @@ With ARG, do it many times.  Negative ARG means move 
backward."
     (treesit-parser-create 'heex)
 
     ;; Comments
-    (setq-local treesit-text-type-regexp
-                (regexp-opt '("comment" "text")))
+    (setq-local treesit-thing-settings
+                `((heex
+                   (text ,(regexp-opt '("comment" "text"))))))
 
     (setq-local forward-sexp-function #'heex-ts--forward-sexp)
 
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index 121c8550be0..863adeb9245 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -317,11 +317,6 @@ Return nil if there is no name or if NODE is not a defun 
node."
   ;; Comments.
   (c-ts-common-comment-setup)
 
-  (setq-local treesit-text-type-regexp
-              (regexp-opt '("line_comment"
-                            "block_comment"
-                            "text_block")))
-
   ;; Indent.
   (setq-local c-ts-common-indent-type-regexp-alist
               `((block . ,(rx (or "class_body"
@@ -360,28 +355,30 @@ Return nil if there is no name or if NODE is not a defun 
node."
                             "constructor_declaration")))
   (setq-local treesit-defun-name-function #'java-ts-mode--defun-name)
 
-  (setq-local treesit-sentence-type-regexp
-              (regexp-opt '("statement"
-                            "local_variable_declaration"
-                            "field_declaration"
-                            "module_declaration"
-                            "package_declaration"
-                            "import_declaration")))
-
-  (setq-local treesit-sexp-type-regexp
-              (regexp-opt '("annotation"
-                            "parenthesized_expression"
-                            "argument_list"
-                            "identifier"
-                            "modifiers"
-                            "block"
-                            "body"
-                            "literal"
-                            "access"
-                            "reference"
-                            "_type"
-                            "true"
-                            "false")))
+  (setq-local treesit-thing-settings
+              `(java
+                (sexp ,(rx (or "annotation"
+                               "parenthesized_expression"
+                               "argument_list"
+                               "identifier"
+                               "modifiers"
+                               "block"
+                               "body"
+                               "literal"
+                               "access"
+                               "reference"
+                               "_type"
+                               "true"
+                               "false")))
+                (sentence ,(rx (or "statement"
+                                   "local_variable_declaration"
+                                   "field_declaration"
+                                   "module_declaration"
+                                   "package_declaration"
+                                   "import_declaration")))
+                (text ,(regexp-opt '("line_comment"
+                                     "block_comment"
+                                     "text_block")))))
 
   ;; Font-lock.
   (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 1d89b35aa2d..feebeae010d 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3831,7 +3831,7 @@ Currently there are `js-mode' and `js-ts-mode'."
     "jsx_element"
     "jsx_self_closing_element")
   "Nodes that designate sentences in JavaScript.
-See `treesit-sentence-type-regexp' for more information.")
+See `treesit-thing-settings' for more information.")
 
 (defvar js--treesit-sexp-nodes
   '("expression"
@@ -3873,15 +3873,12 @@ See `treesit-sexp-type-regexp' for more information.")
     (c-ts-common-comment-setup)
     (setq-local comment-multi-line t)
 
-    (setq-local treesit-text-type-regexp
-                (regexp-opt '("comment"
-                              "template_string")))
-
     ;; Electric-indent.
     (setq-local electric-indent-chars
                 (append "{}():;,<>/" electric-indent-chars)) ;FIXME: js2-mode 
adds "[]*".
     (setq-local electric-layout-rules
                '((?\; . after) (?\{ . after) (?\} . before)))
+    (setq-local syntax-propertize-function #'js-ts--syntax-propertize)
 
     ;; Tree-sitter setup.
     (treesit-parser-create 'javascript)
@@ -3896,11 +3893,12 @@ See `treesit-sexp-type-regexp' for more information.")
                         "lexical_declaration")))
     (setq-local treesit-defun-name-function #'js--treesit-defun-name)
 
-    (setq-local treesit-sentence-type-regexp
-                (regexp-opt js--treesit-sentence-nodes))
-
-    (setq-local treesit-sexp-type-regexp
-                (regexp-opt js--treesit-sexp-nodes))
+    (setq-local treesit-thing-settings
+                `((javascript
+                   (sexp ,(regexp-opt js--treesit-sexp-nodes))
+                   (sentence ,(regexp-opt js--treesit-sentence-nodes))
+                   (text ,(regexp-opt '("comment"
+                                        "template_string"))))))
 
     ;; Fontification.
     (setq-local treesit-font-lock-settings js--treesit-font-lock-settings)
@@ -3924,6 +3922,29 @@ See `treesit-sexp-type-regexp' for more information.")
     (add-to-list 'auto-mode-alist
                  '("\\(\\.js[mx]\\|\\.har\\)\\'" . js-ts-mode))))
 
+(defvar js-ts--s-p-query
+  (when (treesit-available-p)
+    (treesit-query-compile 'javascript
+                           '(((regex pattern: (regex_pattern) @regexp))
+                             ((variable_declarator value: (jsx_element) @jsx))
+                             ((assignment_expression right: (jsx_element) 
@jsx))
+                             ((return_statement (jsx_element) @jsx))))))
+
+(defun js-ts--syntax-propertize (beg end)
+  (let ((captures (treesit-query-capture 'javascript js-ts--s-p-query beg 
end)))
+    (pcase-dolist (`(,name . ,node) captures)
+      (let* ((ns (treesit-node-start node))
+             (ne (treesit-node-end node))
+             (syntax (pcase-exhaustive name
+                       ('regexp
+                        (cl-decf ns)
+                        (cl-incf ne)
+                        (string-to-syntax "\"/"))
+                       ('jsx
+                        (string-to-syntax "|")))))
+        (put-text-property ns (1+ ns) 'syntax-table syntax)
+        (put-text-property (1- ne) ne 'syntax-table syntax)))))
+
 ;;;###autoload
 (define-derived-mode js-json-mode js-mode "JSON"
   (setq-local js-enabled-frameworks nil)
diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el
index f56d118c0fe..78117356821 100644
--- a/lisp/progmodes/json-ts-mode.el
+++ b/lisp/progmodes/json-ts-mode.el
@@ -147,7 +147,9 @@ Return nil if there is no name or if NODE is not a defun 
node."
               (rx (or "pair" "object")))
   (setq-local treesit-defun-name-function #'json-ts-mode--defun-name)
 
-  (setq-local treesit-sentence-type-regexp "pair")
+  (setq-local treesit-thing-settings
+              `((json
+                 (sentence "pair"))))
 
   ;; Font-lock.
   (setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings)
diff --git a/lisp/progmodes/make-mode.el b/lisp/progmodes/make-mode.el
index ff2aa137813..37e4c439dca 100644
--- a/lisp/progmodes/make-mode.el
+++ b/lisp/progmodes/make-mode.el
@@ -44,10 +44,6 @@
 ;; prerequisites, which targets are out-of-date, and which have no
 ;; prerequisites.
 ;;
-;; The command C-c C-b pops up a browser window listing all target and
-;; macro names.  You can mark or unmark items with C-c SPC, and insert
-;; all marked items back in the Makefile with C-c TAB.
-;;
 ;; The command C-c TAB in the makefile buffer inserts a GNU make builtin.
 ;; You will be prompted for the builtin's arguments.
 ;;
@@ -66,17 +62,9 @@
 ;;   interact with font-lock.
 ;; * Would be nice to edit the commands in ksh-mode and have
 ;;   indentation and slashification done automatically.  Hard.
-;; * Consider removing browser mode.  It seems useless.
 ;; * ":" should notice when a new target is made and add it to the
 ;;   list (or at least set `makefile-need-target-pickup').
-;; * Make browser into a major mode.
 ;; * Clean up macro insertion stuff.  It is a mess.
-;; * Browser entry and exit is weird.  Normalize.
-;; * Browser needs to be rewritten.  Right now it is kind of a crock.
-;;   Should at least:
-;;    * Act more like dired/buffer menu/whatever.
-;;    * Highlight as mouse traverses.
-;;    * B2 inserts.
 ;; * Update documentation above.
 ;; * Update texinfo manual.
 ;; * Update files.el.
@@ -118,6 +106,7 @@
   "Face to use for additionally highlighting Perl code in Font-Lock mode."
   :version "22.1")
 
+(make-obsolete-variable 'makefile-browser-buffer-name nil "30.1")
 (defcustom makefile-browser-buffer-name "*Macros and Targets*"
   "Name of the macro- and target browser buffer."
   :type 'string)
@@ -152,10 +141,12 @@ Otherwise, a space is inserted.
 The default is t."
   :type 'boolean)
 
+(make-obsolete-variable 'makefile-browser-leftmost-column nil "30.1")
 (defcustom makefile-browser-leftmost-column 10
   "Number of blanks to the left of the browser selection mark."
   :type 'integer)
 
+(make-obsolete-variable 'makefile-browser-cursor-column nil "30.1")
 (defcustom makefile-browser-cursor-column 10
   "Column the cursor goes to when it moves up or down in the Makefile browser."
   :type 'integer)
@@ -168,14 +159,17 @@ The default is t."
   "If non-nil, `makefile-backslash-region' will align backslashes."
   :type 'boolean)
 
+(make-obsolete-variable 'makefile-browser-selected-mark nil "30.1")
 (defcustom makefile-browser-selected-mark "+  "
   "String used to mark selected entries in the Makefile browser."
   :type 'string)
 
+(make-obsolete-variable 'makefile-browser-unselected-mark nil "30.1")
 (defcustom makefile-browser-unselected-mark "   "
   "String used to mark unselected entries in the Makefile browser."
   :type 'string)
 
+(make-obsolete-variable 'makefile-browser-auto-advance-after-selection-p nil 
"30.1")
 (defcustom makefile-browser-auto-advance-after-selection-p t
   "If non-nil, cursor will move after item is selected in Makefile browser."
   :type 'boolean)
@@ -198,6 +192,7 @@ to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems 
necessary\"."
   "Normal hook run by `makefile-mode'."
   :type 'hook)
 
+(make-obsolete-variable 'makefile-browser-hook nil "30.1")
 (defvar makefile-browser-hook '())
 
 ;;
@@ -611,9 +606,6 @@ The function must satisfy this calling convention:
     ;; Other.
     ["Up To Date Overview" makefile-create-up-to-date-overview
      :help "Create a buffer containing an overview of the state of all known 
targets"]
-    ["Pop up Makefile Browser" makefile-switch-to-browser
-     ;; XXX: this needs a better string, the function is not documented...
-     :help "Pop up Makefile Browser"]
     ("Switch Makefile Type"
      ["GNU make" makefile-gmake-mode
       :help "An adapted `makefile-mode' that knows about GNU make"
@@ -641,6 +633,7 @@ The function must satisfy this calling convention:
       :selected (eq major-mode 'makefile-makepp-mode)])))
 
 
+(make-obsolete-variable 'makefile-browser-map nil "30.1")
 (defvar-keymap makefile-browser-map
   :doc "The keymap that is used in the macro- and target browser."
   "n"       #'makefile-browser-next-line
@@ -695,9 +688,11 @@ The function must satisfy this calling convention:
   "Table of all macro names known for this buffer.")
 (put 'makefile-macro-table 'risky-local-variable t)
 
+(make-obsolete-variable 'makefile-browser-client nil "30.1")
 (defvar makefile-browser-client nil
   "A buffer in Makefile mode that is currently using the browser.")
 
+(make-obsolete-variable 'makefile-browser-selection-vector nil "30.1")
 (defvar makefile-browser-selection-vector nil)
 (defvar makefile-has-prereqs nil)
 (defvar makefile-need-target-pickup t)
@@ -757,15 +752,8 @@ dependency, despite the colon.
 
 \\{makefile-mode-map}
 
-In the browser, use the following keys:
-
-\\{makefile-browser-map}
-
 Makefile mode can be configured by modifying the following variables:
 
-`makefile-browser-buffer-name':
-    Name of the macro- and target browser buffer.
-
 `makefile-target-colon':
     The string that gets appended to all target names
     inserted by `makefile-insert-target'.
@@ -783,24 +771,6 @@ Makefile mode can be configured by modifying the following 
variables:
    If you want a TAB (instead of a space) to be appended after the
    target colon, then set this to a non-nil value.
 
-`makefile-browser-leftmost-column':
-   Number of blanks to the left of the browser selection mark.
-
-`makefile-browser-cursor-column':
-   Column in which the cursor is positioned when it moves
-   up or down in the browser.
-
-`makefile-browser-selected-mark':
-   String used to mark selected entries in the browser.
-
-`makefile-browser-unselected-mark':
-   String used to mark unselected entries in the browser.
-
-`makefile-browser-auto-advance-after-selection-p':
-   If this variable is set to a non-nil value the cursor
-   will automagically advance to the next line after an item
-   has been selected in the browser.
-
 `makefile-pickup-everything-picks-up-filenames-p':
    If this variable is set to a non-nil value then
    `makefile-pickup-everything' also picks up filenames as targets
@@ -816,10 +786,6 @@ Makefile mode can be configured by modifying the following 
variables:
    IMPORTANT: Please note that enabling this option causes Makefile mode
    to MODIFY A FILE WITHOUT YOUR CONFIRMATION when \"it seems necessary\".
 
-`makefile-browser-hook':
-   A function or list of functions to be called just before the
-   browser is entered. This is executed in the makefile buffer.
-
 `makefile-special-targets-list':
    List of special targets. You will be offered to complete
    on one of those in the minibuffer whenever you enter a `.'.
@@ -1306,6 +1272,7 @@ Fill comments, backslashed lines, and variable 
definitions specially."
 ;;; ------------------------------------------------------------
 
 (defun makefile-browser-format-target-line (target selected)
+  (declare (obsolete nil "30.1"))
   (format
    (concat (make-string makefile-browser-leftmost-column ?\ )
           (if selected
@@ -1315,6 +1282,7 @@ Fill comments, backslashed lines, and variable 
definitions specially."
    target makefile-target-colon))
 
 (defun makefile-browser-format-macro-line (macro selected)
+  (declare (obsolete nil "30.1"))
   (format
    (concat (make-string makefile-browser-leftmost-column ?\ )
           (if selected
@@ -1323,14 +1291,21 @@ Fill comments, backslashed lines, and variable 
definitions specially."
           (makefile-format-macro-ref macro))))
 
 (defun makefile-browser-fill (targets macros)
+  (declare (obsolete nil "30.1"))
   (let ((inhibit-read-only t))
     (goto-char (point-min))
     (erase-buffer)
     (mapc
-     (lambda (item) (insert (makefile-browser-format-target-line (car item) 
nil) "\n"))
+     (lambda (item) (insert (with-suppressed-warnings
+                                ((obsolete 
makefile-browser-format-target-line))
+                              (makefile-browser-format-target-line (car item) 
nil))
+                            "\n"))
      targets)
     (mapc
-     (lambda (item) (insert (makefile-browser-format-macro-line (car item) 
nil) "\n"))
+     (lambda (item) (insert (with-suppressed-warnings
+                                ((obsolete makefile-browser-format-macro-line))
+                              (makefile-browser-format-macro-line (car item) 
nil))
+                            "\n"))
      macros)
     (sort-lines nil (point-min) (point-max))
     (goto-char (1- (point-max)))
@@ -1344,6 +1319,7 @@ Fill comments, backslashed lines, and variable 
definitions specially."
 
 (defun makefile-browser-next-line ()
   "Move the browser selection cursor to the next line."
+  (declare (obsolete nil "30.1"))
   (interactive)
   (unless (makefile-last-line-p)
     (forward-line 1)
@@ -1351,6 +1327,7 @@ Fill comments, backslashed lines, and variable 
definitions specially."
 
 (defun makefile-browser-previous-line ()
   "Move the browser selection cursor to the previous line."
+  (declare (obsolete nil "30.1"))
   (interactive)
   (unless (makefile-first-line-p)
     (forward-line -1)
@@ -1362,6 +1339,7 @@ Fill comments, backslashed lines, and variable 
definitions specially."
 
 (defun makefile-browser-quit ()
   "Leave the browser and return to the makefile buffer."
+  (declare (obsolete nil "30.1"))
   (interactive)
   (let ((my-client makefile-browser-client))
     (setq makefile-browser-client nil) ; we quit, so NO client!
@@ -1375,6 +1353,7 @@ Fill comments, backslashed lines, and variable 
definitions specially."
 
 (defun makefile-browser-toggle ()
   "Toggle the selection state of the browser item at the cursor position."
+  (declare (obsolete nil "30.1"))
   (interactive)
   (let ((this-line (count-lines (point-min) (point))))
     (setq this-line (max 1 this-line))
@@ -1387,19 +1366,24 @@ Fill comments, backslashed lines, and variable 
definitions specially."
          (let ((macro-name (makefile-browser-this-line-macro-name)))
            (delete-region (point) (progn (end-of-line) (point)))
            (insert
-            (makefile-browser-format-macro-line
-               macro-name
-               (makefile-browser-get-state-for-line this-line))))
+             (with-suppressed-warnings
+                 ((obsolete makefile-browser-format-macro-line))
+               (makefile-browser-format-macro-line
+                macro-name
+                (makefile-browser-get-state-for-line this-line)))))
        (let ((target-name (makefile-browser-this-line-target-name)))
          (delete-region (point) (progn (end-of-line) (point)))
          (insert
-          (makefile-browser-format-target-line
-             target-name
-             (makefile-browser-get-state-for-line this-line))))))
+           (with-suppressed-warnings
+               ((obsolete makefile-browser-format-target-line))
+             (makefile-browser-format-target-line
+              target-name
+              (makefile-browser-get-state-for-line this-line)))))))
     (beginning-of-line)
     (forward-char makefile-browser-cursor-column)
     (if makefile-browser-auto-advance-after-selection-p
-       (makefile-browser-next-line))))
+        (with-suppressed-warnings ((obsolete makefile-browser-next-line))
+          (makefile-browser-next-line)))))
 
 ;;;
 ;;; Making insertions into the client buffer
@@ -1412,6 +1396,7 @@ character, insert a new blank line, go to that line and 
indent by one TAB.
 This is most useful in the process of creating continued lines when copying
 large dependencies from the browser to the client buffer.
 \(point) advances accordingly in the client buffer."
+  (declare (obsolete nil "30.1"))
   (interactive)
   (with-current-buffer makefile-browser-client
     (end-of-line)
@@ -1420,6 +1405,7 @@ large dependencies from the browser to the client buffer.
 (defun makefile-browser-insert-selection ()
   "Insert all selected targets and/or macros in the makefile buffer.
 Insertion takes place at point."
+  (declare (obsolete nil "30.1"))
   (interactive)
   (save-excursion
     (goto-char (point-min))
@@ -1431,11 +1417,15 @@ Insertion takes place at point."
        (setq current-line (1+ current-line))))))
 
 (defun makefile-browser-insert-selection-and-quit ()
+  (declare (obsolete nil "30.1"))
   (interactive)
-  (makefile-browser-insert-selection)
-  (makefile-browser-quit))
+  (with-suppressed-warnings ((obsolete makefile-browser-insert-selection)
+                             (obsolete makefile-browser-quit))
+    (makefile-browser-insert-selection)
+    (makefile-browser-quit)))
 
 (defun makefile-browser-send-this-line-item ()
+  (declare (obsolete nil "30.1"))
   (if (makefile-browser-on-macro-line-p)
       (save-excursion
        (let ((macro-name (makefile-browser-this-line-macro-name)))
@@ -1447,10 +1437,12 @@ Insertion takes place at point."
        (insert target-name " ")))))
 
 (defun makefile-browser-start-interaction ()
+  (declare (obsolete nil "30.1"))
   (use-local-map makefile-browser-map)
   (setq buffer-read-only t))
 
 (defun makefile-browse (targets macros)
+  (declare (obsolete imenu "30.1"))
   (if (zerop (+ (length targets) (length macros)))
       (progn
        (beep)
@@ -1460,19 +1452,23 @@ Insertion takes place at point."
                   "Consider running \\[makefile-pickup-everything]"))))
     (let ((browser-buffer (get-buffer-create makefile-browser-buffer-name)))
       (pop-to-buffer browser-buffer)
-      (makefile-browser-fill targets macros)
+      (with-suppressed-warnings ((obsolete makefile-browser-fill))
+        (makefile-browser-fill targets macros))
       (shrink-window-if-larger-than-buffer)
       (setq-local makefile-browser-selection-vector
                   (make-vector (+ (length targets) (length macros)) nil))
-      (makefile-browser-start-interaction))))
+      (with-suppressed-warnings ((obsolete makefile-browser-start-interaction))
+        (makefile-browser-start-interaction)))))
 
 (defun makefile-switch-to-browser ()
+  (declare (obsolete imenu "30.1"))
   (interactive)
   (run-hooks 'makefile-browser-hook)
   (setq makefile-browser-client (current-buffer))
   (makefile-pickup-targets)
   (makefile-pickup-macros)
-  (makefile-browse makefile-target-table makefile-macro-table))
+  (with-suppressed-warnings ((obsolete makefile-browse))
+    (makefile-browse makefile-target-table makefile-macro-table)))
 
 
 
@@ -1724,12 +1720,14 @@ This acts according to the value of 
`makefile-tab-after-target-colon'."
 
 (defun makefile-browser-on-macro-line-p ()
   "Determine if point is on a macro line in the browser."
+  (declare (obsolete nil "30.1"))
   (save-excursion
     (beginning-of-line)
     (re-search-forward "\\$[{(]" (line-end-position) t)))
 
 (defun makefile-browser-this-line-target-name ()
   "Extract the target name from a line in the browser."
+  (declare (obsolete nil "30.1"))
   (save-excursion
     (end-of-line)
     (skip-chars-backward "^ \t")
@@ -1737,6 +1735,7 @@ This acts according to the value of 
`makefile-tab-after-target-colon'."
 
 (defun makefile-browser-this-line-macro-name ()
   "Extract the macro name from a line in the browser."
+  (declare (obsolete nil "30.1"))
   (save-excursion
     (beginning-of-line)
     (re-search-forward "\\$[{(]" (line-end-position) t)
@@ -1755,13 +1754,18 @@ Uses `makefile-use-curly-braces-for-macros-p'."
       (format "$(%s)" macro-name))))
 
 (defun makefile-browser-get-state-for-line (n)
+  (declare (obsolete nil "30.1"))
   (aref makefile-browser-selection-vector (1- n)))
 
 (defun makefile-browser-set-state-for-line (n to-state)
+  (declare (obsolete nil "30.1"))
   (aset makefile-browser-selection-vector (1- n) to-state))
 
 (defun makefile-browser-toggle-state-for-line (n)
-  (makefile-browser-set-state-for-line n (not 
(makefile-browser-get-state-for-line n))))
+  (declare (obsolete nil "30.1"))
+  (with-suppressed-warnings ((obsolete makefile-browser-set-state-for-line)
+                             (obsolete makefile-browser-get-state-for-line))
+    (makefile-browser-set-state-for-line n (not 
(makefile-browser-get-state-for-line n)))))
 
 (defun makefile-last-line-p ()
   (= (line-end-position) (point-max)))
diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el
index 16497097061..f5e6e117d99 100644
--- a/lisp/progmodes/prog-mode.el
+++ b/lisp/progmodes/prog-mode.el
@@ -37,6 +37,7 @@
 (declare-function treesit-parser-list "treesit.c")
 (declare-function treesit-node-type "treesit.c")
 (declare-function treesit-node-at "treesit.c")
+(declare-function treesit-node-match-p "treesit.c")
 
 (defgroup prog-mode nil
   "Generic programming mode, from which others derive."
@@ -160,9 +161,8 @@ or follows point."
     (let ((treesit-text-node
            (and (treesit-available-p)
                 (treesit-parser-list)
-                (string-match-p
-                 treesit-text-type-regexp
-                 (treesit-node-type (treesit-node-at (point)))))))
+                (treesit-node-match-p
+                 (treesit-node-at (point)) 'text t))))
       (if (or treesit-text-node
               (nth 8 (syntax-ppss))
               (re-search-forward "\\s-*\\s<" (line-end-position) t))
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 7aaf7a9f9fb..29a81c7e151 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -410,7 +410,8 @@ the buffer's value of `default-directory'."
 (defcustom project-vc-ignores nil
   "List of patterns to add to `project-ignores'."
   :type '(repeat string))
-;;;###autoload(put 'project-vc-ignores 'safe-local-variable #'listp)
+;; Change to `list-of-strings-p' when support for Emacs 28 is dropped.
+;;;###autoload(put 'project-vc-ignores 'safe-local-variable (lambda (val) (and 
(listp val) (not (memq nil (mapcar #'stringp val))))))
 
 (defcustom project-vc-merge-submodules t
   "Non-nil to consider submodules part of the parent project.
@@ -465,6 +466,7 @@ variables, such as `project-vc-ignores' or 
`project-vc-name'."
   :type '(repeat string)
   :version "29.1"
   :package-version '(project . "0.9.0"))
+;; Change to `list-of-strings-p' when support for Emacs 28 is dropped.
 ;;;###autoload(put 'project-vc-extra-root-markers 'safe-local-variable (lambda 
(val) (and (listp val) (not (memq nil (mapcar #'stringp val))))))
 
 ;; FIXME: Using the current approach, major modes are supposed to set
@@ -731,11 +733,10 @@ See `project-vc-extra-root-markers' for the marker value 
format.")
 
 (cl-defmethod project-ignores ((project (head vc)) dir)
   (let* ((root (nth 2 project))
-         backend)
+         (backend (cadr project)))
     (append
      (when (and backend
                 (file-equal-p dir root))
-       (setq backend (cadr project))
        (delq
         nil
         (mapcar
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index adbf18786cb..fabe5859779 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -1122,44 +1122,45 @@ leading double colon is not added."
   ;; Navigation.
   (setq-local treesit-defun-type-regexp ruby-ts--method-regex)
 
-  (setq-local treesit-sexp-type-regexp
-              (cons (rx
-                     bol
-                     (or
-                      "class"
-                      "module"
-                      "method"
-                      "array"
-                      "hash"
-                      "parenthesized_statements"
-                      "method_parameters"
-                      "array_pattern"
-                      "hash_pattern"
-                      "if"
-                      "unless"
-                      "case"
-                      "case_match"
-                      "when"
-                      "block"
-                      "do_block"
-                      "begin"
-                      "integer"
-                      "identifier"
-                      "constant"
-                      "simple_symbol"
-                      "hash_key_symbol"
-                      "symbol_array"
-                      "string"
-                      "string_array"
-                      "heredoc_body"
-                      "regex"
-                      "argument_list"
-                      "interpolation"
-                      "instance_variable"
-                      "global_variable"
-                      )
-                     eol)
-                    #'ruby-ts--sexp-p))
+  (setq-local treesit-thing-settings
+              `((ruby
+                 (sexp ,(cons (rx
+                               bol
+                               (or
+                                "class"
+                                "module"
+                                "method"
+                                "array"
+                                "hash"
+                                "parenthesized_statements"
+                                "method_parameters"
+                                "array_pattern"
+                                "hash_pattern"
+                                "if"
+                                "unless"
+                                "case"
+                                "case_match"
+                                "when"
+                                "block"
+                                "do_block"
+                                "begin"
+                                "integer"
+                                "identifier"
+                                "constant"
+                                "simple_symbol"
+                                "hash_key_symbol"
+                                "symbol_array"
+                                "string"
+                                "string_array"
+                                "heredoc_body"
+                                "regex"
+                                "argument_list"
+                                "interpolation"
+                                "instance_variable"
+                                "global_variable"
+                                )
+                               eol)
+                              #'ruby-ts--sexp-p)))))
 
   ;; AFAIK, Ruby can not nest methods
   (setq-local treesit-defun-prefer-top-level nil)
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index ed4ea8e3618..cc521cb0591 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1629,10 +1629,11 @@ not written in Bash or sh."
                   ( bracket delimiter misc-punctuation operator)))
     (setq-local treesit-font-lock-settings
                 sh-mode--treesit-settings)
-    (setq-local treesit-text-type-regexp
-                (regexp-opt '("comment"
-                              "heredoc_start"
-                              "heredoc_body")))
+    (setq-local treesit-thing-settings
+                `((bash
+                   (sentence ,(regexp-opt '("comment"
+                                            "heredoc_start"
+                                            "heredoc_body"))))))
     (setq-local treesit-defun-type-regexp "function_definition")
     (treesit-major-mode-setup)))
 
diff --git a/lisp/progmodes/typescript-ts-mode.el 
b/lisp/progmodes/typescript-ts-mode.el
index 3f8e232b71f..441cdc1f7aa 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -387,7 +387,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
     "lexical_declaration"
     "property_signature")
   "Nodes that designate sentences in TypeScript.
-See `treesit-sentence-type-regexp' for more information.")
+See `treesit-thing-settings' for more information.")
 
 (defvar typescript-ts-mode--sexp-nodes
   '("expression"
@@ -409,7 +409,7 @@ See `treesit-sentence-type-regexp' for more information.")
     "arguments"
     "pair")
   "Nodes that designate sexps in TypeScript.
-See `treesit-sexp-type-regexp' for more information.")
+See `treesit-thing-settings' for more information.")
 
 ;;;###autoload
 (define-derived-mode typescript-ts-base-mode prog-mode "TypeScript"
@@ -421,10 +421,6 @@ See `treesit-sexp-type-regexp' for more information.")
   (c-ts-common-comment-setup)
   (setq-local treesit-defun-prefer-top-level t)
 
-  (setq-local treesit-text-type-regexp
-              (regexp-opt '("comment"
-                            "template_string")))
-
   ;; Electric
   (setq-local electric-indent-chars
               (append "{}():;,<>/" electric-indent-chars))
@@ -438,11 +434,13 @@ See `treesit-sexp-type-regexp' for more information.")
                             "lexical_declaration")))
   (setq-local treesit-defun-name-function #'js--treesit-defun-name)
 
-  (setq-local treesit-sentence-type-regexp
-              (regexp-opt typescript-ts-mode--sentence-nodes))
-
-  (setq-local treesit-sexp-type-regexp
-              (regexp-opt typescript-ts-mode--sexp-nodes))
+  (setq-local treesit-thing-settings
+              `((typescript
+                 (sexp ,(regexp-opt typescript-ts-mode--sexp-nodes))
+                 (sentence ,(regexp-opt
+                             typescript-ts-mode--sentence-nodes))
+                 (text ,(regexp-opt '("comment"
+                                      "template_string"))))))
 
   ;; Imenu (same as in `js-ts-mode').
   (setq-local treesit-simple-imenu-settings
@@ -513,17 +511,15 @@ at least 3 (which is the default value)."
     (setq-local treesit-simple-indent-rules
                 (typescript-ts-mode--indent-rules 'tsx))
 
-    ;; Navigation
-    (setq-local treesit-sentence-type-regexp
-                (regexp-opt (append
-                             typescript-ts-mode--sentence-nodes
-                             '("jsx_element"
-                               "jsx_self_closing_element"))))
-
-  (setq-local treesit-sexp-type-regexp
-              (regexp-opt (append
-                           typescript-ts-mode--sexp-nodes
-                           '("jsx"))))
+    (setq-local treesit-thing-settings
+                `((tsx
+                   (sexp ,(regexp-opt
+                           (append typescript-ts-mode--sexp-nodes
+                                   '("jsx"))))
+                   (sentence ,(regexp-opt
+                               (append typescript-ts-mode--sentence-nodes
+                                       '("jsx_element"
+                                         "jsx_self_closing_element")))))))
 
     ;; Font-lock.
     (setq-local treesit-font-lock-settings
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 3f75f8d7132..b7bfb192d87 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -1468,7 +1468,6 @@ The meanings of both arguments are the same as documented 
in
   (xref--show-xrefs fetcher display-action))
 
 (defun xref--show-xrefs (fetcher display-action &optional _always-show-list)
-  (xref--push-markers)
   (unless (functionp fetcher)
     ;; Old convention.
     (let ((xrefs fetcher))
@@ -1479,21 +1478,32 @@ The meanings of both arguments are the same as 
documented in
                 (prog1
                     xrefs
                   (setq xrefs 'called-already)))))))
-  (funcall xref-show-xrefs-function fetcher
-           `((window . ,(selected-window))
-             (display-action . ,display-action)
-             (auto-jump . ,xref-auto-jump-to-first-xref))))
+  (let ((cb (current-buffer))
+        (pt (point)))
+    (prog1
+        (funcall xref-show-xrefs-function fetcher
+                 `((window . ,(selected-window))
+                   (display-action . ,display-action)
+                   (auto-jump . ,xref-auto-jump-to-first-xref)))
+      (xref--push-markers cb pt))))
 
 (defun xref--show-defs (xrefs display-action)
-  (xref--push-markers)
-  (funcall xref-show-definitions-function xrefs
-           `((window . ,(selected-window))
-             (display-action . ,display-action)
-             (auto-jump . ,xref-auto-jump-to-first-definition))))
-
-(defun xref--push-markers ()
-  (unless (region-active-p) (push-mark nil t))
-  (xref-push-marker-stack))
+  (let ((cb (current-buffer))
+        (pt (point)))
+    (prog1
+        (funcall xref-show-definitions-function xrefs
+                 `((window . ,(selected-window))
+                   (display-action . ,display-action)
+                   (auto-jump . ,xref-auto-jump-to-first-definition)))
+      (xref--push-markers cb pt))))
+
+(defun xref--push-markers (buf pt)
+  (when (buffer-live-p buf)
+    (save-excursion
+      (with-no-warnings (set-buffer buf))
+      (goto-char pt)
+      (unless (region-active-p) (push-mark nil t))
+      (xref-push-marker-stack))))
 
 (defun xref--prompt-p (command)
   (or (eq xref-prompt-for-identifier t)
@@ -1638,7 +1648,9 @@ This command is intended to be bound to a mouse event."
            (mouse-set-point event)
            (xref-backend-identifier-at-point (xref-find-backend)))))
     (if identifier
-        (xref-find-definitions identifier)
+        (progn
+          (mouse-set-point event)
+          (xref-find-definitions identifier))
       (user-error "No identifier here"))))
 
 ;;;###autoload
@@ -1652,6 +1664,7 @@ This command is intended to be bound to a mouse event."
            (xref-backend-identifier-at-point (xref-find-backend)))))
     (if identifier
         (let ((xref-prompt-for-identifier nil))
+          (mouse-set-point event)
           (xref-find-references identifier))
       (user-error "No identifier here"))))
 
diff --git a/lisp/ps-print.el b/lisp/ps-print.el
index b54f09b2bdd..aa3037f5273 100644
--- a/lisp/ps-print.el
+++ b/lisp/ps-print.el
@@ -4850,17 +4850,6 @@ page-height == ((floor print-height ((th + ls) * zh)) * 
((th + ls) * zh)) - th
     (and has-local-background (ps-output "}def\n"))))
 
 
-;; Return a list of the distinct elements of LIST.
-;; Elements are compared with `equal'.
-(defun ps-remove-duplicates (list)
-  (let (new (tail list))
-    (while tail
-      (or (member (car tail) new)
-         (setq new (cons (car tail) new)))
-      (setq tail (cdr tail)))
-    (nreverse new)))
-
-
 ;; Find the first occurrence of ITEM in LIST.
 ;; Return the index of the matching item, or nil if not found.
 ;; Elements are compared with `eq'.
@@ -5342,7 +5331,7 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
      (if ps-landscape-mode "Landscape" "Portrait")
      "\n%%DocumentNeededResources: font Times-Roman Times-Italic\n%%+ font "
      (mapconcat 'identity
-               (ps-remove-duplicates
+                (seq-uniq
                 (append (ps-fonts 'ps-font-for-text)
                         (list (ps-font 'ps-font-for-header 'normal)
                               (ps-font 'ps-font-for-header 'bold)
@@ -5491,7 +5480,7 @@ XSTART YSTART are the relative position for the first 
page in a sheet.")
      "\n%%IncludeResource: font Times-Italic"
      "\n%%IncludeResource: font "
      (mapconcat 'identity
-               (ps-remove-duplicates
+                (seq-uniq
                 (append (ps-fonts 'ps-font-for-text)
                         (list (ps-font 'ps-font-for-header 'normal)
                               (ps-font 'ps-font-for-header 'bold)
@@ -6548,6 +6537,7 @@ Please send all bug fixes and enhancements to
 (make-obsolete-variable 'ps-print-version 'emacs-version "29.1")
 
 (define-obsolete-function-alias 'ps-print-ensure-fontified #'font-lock-ensure 
"29.1")
+(define-obsolete-function-alias 'ps-remove-duplicates #'seq-uniq "30.1")
 
 (provide 'ps-print)
 
diff --git a/lisp/startup.el b/lisp/startup.el
index 4d0e59ba4f3..6329e3ea8d0 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -1682,7 +1682,7 @@ Changed settings will be marked as \"CHANGED outside of 
Customize\"."
 
 (defcustom initial-scratch-message (purecopy "\
 ;; This buffer is for text that is not saved, and for Lisp evaluation.
-;; To create a file, visit it with \\[find-file] and enter text in its buffer.
+;; To create a file, visit it with `\\[find-file]' and enter text in its 
buffer.
 
 ")
   "Initial documentation displayed in *scratch* buffer at startup.
diff --git a/lisp/strokes.el b/lisp/strokes.el
index 694677ada0b..5bfcab5f9e2 100644
--- a/lisp/strokes.el
+++ b/lisp/strokes.el
@@ -266,6 +266,14 @@ able to see the strokes.  This be helpful for people who 
don't like
 the delay in switching to the strokes buffer."
   :type 'boolean)
 
+(defvar strokes-no-match-function 'strokes-no-match-default
+  "Function run by `strokes-execute-stroke' when no stroke matches.
+The function is called with two arguments, the stroke and the
+closest match returned by `strokes-match-stroke'.  It can be used
+to show detailed information about the unmatched stroke or
+perform some fallback action.  The default function
+`strokes-no-match-default' simply signals an error.")
+
 ;;; internal variables...
 
 (defvar strokes-window-configuration nil
@@ -838,14 +846,16 @@ Optional EVENT is acceptable as the starting event of the 
stroke."
            (goto-char (point-min))
            (bury-buffer)))))))
 
+(defun strokes-no-match-default (&rest _)
+  "Signal an error when no stroke matches."
+  (error
+   "No stroke matches; see variable `strokes-minimum-match-score'"))
+
 (defun strokes-execute-stroke (stroke)
   "Given STROKE, execute the command which corresponds to it.
 The command will be executed provided one exists for that stroke,
-based on the variable `strokes-minimum-match-score'.
-If no stroke matches, nothing is done and return value is nil."
-  ;; FIXME: Undocument return value.  It is not documented for all cases,
-  ;; and doesn't allow differentiating between no stroke matches and
-  ;; command-execute returning nil, anyway.
+based on the variable `strokes-minimum-match-score'.  If no
+stroke matches, `strokes-no-match-function' is called."
   (let* ((match (strokes-match-stroke stroke strokes-global-map))
         (command (car match))
         (score (cdr match)))
@@ -859,10 +869,7 @@ If no stroke matches, nothing is done and return value is 
nil."
                                     strokes-file))
                    (strokes-load-user-strokes))
             (error "No strokes defined; use `strokes-global-set-stroke'")))
-         (t
-          (error
-           "No stroke matches; see variable `strokes-minimum-match-score'")
-          nil))))
+         (t (funcall strokes-no-match-function stroke match)))))
 
 ;;;###autoload
 (defun strokes-do-stroke (event)
diff --git a/lisp/subr.el b/lisp/subr.el
index 47fcbc2f317..34d87e83310 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -277,6 +277,21 @@ change the list."
          (macroexp-let2 macroexp-copyable-p x getter
            `(prog1 ,x ,(funcall setter `(cdr ,x))))))))
 
+;; Note: `static-if' can be copied into a package to enable it to be
+;; used in Emacsen older than Emacs 30.1.  If the package is used in
+;; very old Emacsen or XEmacs (in which `eval' takes exactly one
+;; argument) the copy will need amending.
+(defmacro static-if (condition then-form &rest else-forms)
+  "A conditional compilation macro.
+Evaluate CONDITION at macro-expansion time.  If it is non-nil,
+expand the macro to THEN-FORM.  Otherwise expand it to ELSE-FORMS
+enclosed in a `progn' form.  ELSE-FORMS may be empty."
+  (declare (indent 2)
+           (debug (sexp sexp &rest sexp)))
+  (if (eval condition lexical-binding)
+      then-form
+    (cons 'progn else-forms)))
+
 (defmacro when (cond &rest body)
   "If COND yields non-nil, do BODY, else return nil.
 When COND yields non-nil, eval BODY forms sequentially and return
@@ -2021,6 +2036,7 @@ instead; it will indirectly limit the specpdl stack size 
as well.")
 (defalias 'store-match-data #'set-match-data)
 (defalias 'chmod #'set-file-modes)
 (defalias 'mkdir #'make-directory)
+(defalias 'wholenump #'natnump)
 
 ;; These were the XEmacs names, now obsolete:
 (defalias 'point-at-eol #'line-end-position)
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 9a59e480f06..fd9294ed581 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -166,6 +166,7 @@ For easier selection of tabs by their numbers, consider 
customizing
     (define-icon tab-bar-new nil
       `((image "symbols/plus_16.svg" "tabs/new.xpm"
                :face shadow
+               :height (1.0 . em)
                :margin ,tab-bar-button-margin
                :ascent center)
         ;; (emoji "➕")
@@ -195,6 +196,7 @@ For easier selection of tabs by their numbers, consider 
customizing
   (unless (iconp 'tab-bar-menu-bar)
     (define-icon tab-bar-menu-bar nil
       `((image "symbols/menu_16.svg"
+               :height (1.0 . em)
                :margin ,tab-bar-button-margin
                :ascent center)
         ;; (emoji "🍔")
@@ -782,6 +784,31 @@ Return its existing value or a new value."
   (set-frame-parameter frame 'tabs tabs))
 
 
+(defun tab-bar-tab-name-format-truncated (name _tab _i)
+  "Truncate the tab name.
+The maximal length is specified by `tab-bar-tab-name-truncated-max'.
+Append ellipsis `tab-bar-tab-name-ellipsis' at the end."
+  (if (< (length name) tab-bar-tab-name-truncated-max)
+      name
+    (truncate-string-to-width
+     name tab-bar-tab-name-truncated-max nil nil
+     tab-bar-tab-name-ellipsis)))
+
+(defun tab-bar-tab-name-format-hints (name _tab i)
+  "Show absolute numbers on tabs in the tab bar before the tab name.
+It has effect when `tab-bar-tab-hints' is non-nil."
+  (if tab-bar-tab-hints (concat (format "%d " i) name) name))
+
+(defun tab-bar-tab-name-format-close-button (name tab _i)
+  "Show the tab close button.
+The variable `tab-bar-close-button-show' defines when to show it."
+  (if (and tab-bar-close-button-show
+           (not (eq tab-bar-close-button-show
+                    (if (eq (car tab) 'current-tab) 'non-selected 'selected)))
+           tab-bar-close-button)
+      (concat name tab-bar-close-button)
+    name))
+
 (defcustom tab-bar-tab-face-function #'tab-bar-tab-face-default
   "Function to define a tab face.
 Function gets one argument: a tab."
@@ -792,6 +819,38 @@ Function gets one argument: a tab."
 (defun tab-bar-tab-face-default (tab)
   (if (eq (car tab) 'current-tab) 'tab-bar-tab 'tab-bar-tab-inactive))
 
+(defun tab-bar-tab-name-format-face (name tab _i)
+  "Apply the face to the tab name.
+It uses the function `tab-bar-tab-face-function'."
+  (add-face-text-property
+   0 (length name) (funcall tab-bar-tab-face-function tab) t name)
+  name)
+
+(defcustom tab-bar-tab-name-format-functions
+  '(tab-bar-tab-name-format-hints
+    tab-bar-tab-name-format-close-button
+    tab-bar-tab-name-format-face)
+  "Functions called to modify the tab name.
+Each function is called with three arguments: the name returned
+by the previously called modifier, the tab and its number.
+It should return the formatted tab name to display in the tab bar."
+  :type '(repeat
+          (choice (function-item tab-bar-tab-name-format-truncated)
+                  (function-item tab-bar-tab-name-format-hints)
+                  (function-item tab-bar-tab-name-format-close-button)
+                  (function-item tab-bar-tab-name-format-face)
+                  (function :tag "Custom function")))
+  :group 'tab-bar
+  :version "30.1")
+
+(defun tab-bar-tab-name-format-default (tab i)
+  (let ((name (copy-sequence (alist-get 'name tab))))
+    (run-hook-wrapped 'tab-bar-tab-name-format-functions
+                      (lambda (fun)
+                        (setq name (funcall fun name tab i))
+                        nil))
+    name))
+
 (defcustom tab-bar-tab-name-format-function #'tab-bar-tab-name-format-default
   "Function to format a tab name.
 Function gets two arguments, the tab and its number, and should return
@@ -804,19 +863,6 @@ the formatted tab name to display in the tab bar."
   :group 'tab-bar
   :version "28.1")
 
-(defun tab-bar-tab-name-format-default (tab i)
-  (let* ((current-p (eq (car tab) 'current-tab))
-         (name (concat (if tab-bar-tab-hints (format "%d " i) "")
-                       (alist-get 'name tab)
-                       (or (and tab-bar-close-button-show
-                                (not (eq tab-bar-close-button-show
-                                         (if current-p 'non-selected 
'selected)))
-                                tab-bar-close-button)
-                           ""))))
-    (add-face-text-property
-     0 (length name) (funcall tab-bar-tab-face-function tab) t name)
-    name))
-
 (defcustom tab-bar-format '(tab-bar-format-history
                             tab-bar-format-tabs
                             tab-bar-separator
@@ -2241,6 +2287,7 @@ and can restore them."
         (unless (iconp 'tab-bar-back)
           (define-icon tab-bar-back nil
             `((image "symbols/chevron_left_16.svg" "tabs/left-arrow.xpm"
+                     :height (1.0 . em)
                      :margin ,tab-bar-button-margin
                      :ascent center)
               (text " < "))
@@ -2251,6 +2298,7 @@ and can restore them."
         (unless (iconp 'tab-bar-forward)
           (define-icon tab-bar-forward nil
             `((image "symbols/chevron_right_16.svg" "tabs/right-arrow.xpm"
+                     :height (1.0 . em)
                      :margin ,tab-bar-button-margin
                      :ascent center)
               (text " > "))
diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index e277d1fb9ed..bdf1db7033f 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -28,7 +28,7 @@
 ;;; Code:
 
 (require 'cl-lib)
-(require 'seq) ; tab-line.el is not pre-loaded so it's safe to use it here
+(require 'seq)
 (require 'icons)
 
 
@@ -194,6 +194,7 @@ If the value is a function, call it with no arguments."
 (define-icon tab-line-new nil
   `((image "symbols/plus_16.svg" "tabs/new.xpm"
            :face shadow
+           :height (1.0 . em)
            :margin (2 . 0)
            :ascent center)
     (text " + "))
@@ -248,6 +249,7 @@ If nil, don't show it at all."
 (define-icon tab-line-left nil
   `((image "symbols/chevron_left_16.svg" "tabs/left-arrow.xpm"
            :face shadow
+           :height (1.0 . em)
            :margin (2 . 0)
            :ascent center)
     (text " <"))
@@ -265,6 +267,7 @@ If nil, don't show it at all."
 (define-icon tab-line-right nil
   `((image "symbols/chevron_right_16.svg" "tabs/right-arrow.xpm"
            :face shadow
+           :height (1.0 . em)
            :margin (2 . 0)
            :ascent center)
     (text "> "))
diff --git a/lisp/term/android-win.el b/lisp/term/android-win.el
index d425ea401a9..db873c176c8 100644
--- a/lisp/term/android-win.el
+++ b/lisp/term/android-win.el
@@ -1,4 +1,4 @@
-;;; x-win.el --- parse relevant switches and set up for Android  -*- 
lexical-binding:t -*-
+;;; android-win.el --- terminal set up for Android  -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2023 Free Software Foundation, Inc.
 
diff --git a/lisp/textmodes/html-ts-mode.el b/lisp/textmodes/html-ts-mode.el
index 4c1f410a7ef..d08d899c815 100644
--- a/lisp/textmodes/html-ts-mode.el
+++ b/lisp/textmodes/html-ts-mode.el
@@ -94,10 +94,6 @@ Return nil if there is no name or if NODE is not a defun 
node."
 
   (treesit-parser-create 'html)
 
-  ;; Comments.
-  (setq-local treesit-text-type-regexp
-              (regexp-opt '("comment" "text")))
-
   ;; Indent.
   (setq-local treesit-simple-indent-rules html-ts-mode--indent-rules)
 
@@ -106,13 +102,14 @@ Return nil if there is no name or if NODE is not a defun 
node."
 
   (setq-local treesit-defun-name-function #'html-ts-mode--defun-name)
 
-  (setq-local treesit-sentence-type-regexp "tag")
-
-  (setq-local treesit-sexp-type-regexp
-              (regexp-opt '("element"
-                            "text"
-                            "attribute"
-                            "value")))
+  (setq-local treesit-thing-settings
+              `((html
+                 (sexp ,(regexp-opt '("element"
+                                      "text"
+                                      "attribute"
+                                      "value")))
+                 (sentence "tag")
+                 (text ,(regexp-opt '("comment" "text"))))))
 
   ;; Font-lock.
   (setq-local treesit-font-lock-settings html-ts-mode--font-lock-settings)
diff --git a/lisp/textmodes/reftex-vars.el b/lisp/textmodes/reftex-vars.el
index ebe49ae9fef..a153bfb3ec3 100644
--- a/lisp/textmodes/reftex-vars.el
+++ b/lisp/textmodes/reftex-vars.el
@@ -1156,7 +1156,7 @@ immediately offer the correct label menu - otherwise it 
will prompt you for
 a label type.  If you set this variable to nil, RefTeX will always prompt."
   :group 'reftex-referencing-labels
   :type 'boolean)
-;;;###autoload(put 'reftex-guess-label-type 'safe-local-variable (lambda (x) 
(memq x '(nil t))))
+;;;###autoload(put 'reftex-guess-label-type 'safe-local-variable #'booleanp)
 
 (defcustom reftex-format-ref-function nil
   "Function which produces the string to insert as a reference.
diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el
index ae3ae1a198d..0a1fa8580d0 100644
--- a/lisp/textmodes/reftex.el
+++ b/lisp/textmodes/reftex.el
@@ -439,7 +439,7 @@ the label information is recompiled on next use."
         ;; When it is a symbol, remove all other symbols
         (and (symbolp entry)
              (not (memq entry list))
-             (setq list (reftex-remove-symbols-from-list list)))
+             (setq list (seq-remove #'symbolp list)))
         ;; Add to list unless already member
         (unless (member entry list)
           (setq reftex-tables-dirty t
@@ -1820,15 +1820,6 @@ When DIE is non-nil, throw an error if file not found."
       (push (pop list) rtn))
     (nreverse rtn)))
 
-(defun reftex-remove-symbols-from-list (list)
-  ;; Remove all symbols from list
-  (let (rtn)
-    (while list
-      (unless (symbolp (car list))
-        (push (car list) rtn))
-      (setq list (cdr list)))
-    (nreverse rtn)))
-
 (defun reftex-uniquify (list &optional sort)
   ;; Return a list of all strings in LIST, but each only once, keeping order
   ;; unless SORT is set (faster!).
@@ -2336,6 +2327,10 @@ Your bug report will be posted to the AUCTeX bug 
reporting list.
   (declare (obsolete "use variable `reftex-use-fonts' instead." "30.1"))
   reftex-use-fonts)
 
+(defun reftex-remove-symbols-from-list (list)
+  (declare (obsolete seq-remove "30.1"))
+  (seq-remove #'symbolp list))
+
 (provide 'reftex)
 
 ;;; reftex.el ends here
diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el
index 577c993efcf..23c5bbf71ff 100644
--- a/lisp/touch-screen.el
+++ b/lisp/touch-screen.el
@@ -1034,6 +1034,10 @@ If the fourth element of `touch-screen-current-tool' is
 original position of the tool to display its bound keymap as a
 menu.
 
+If the fourth element of `touch-screen-current-tool' is `drag' or
+`held', the region is active, and the tool's initial window's
+selected buffer isn't read-only, display the on screen keyboard.
+
 If the command being executed is listed in
 `touch-screen-set-point-commands' also display the on-screen
 keyboard if the current buffer and the character at the new point
@@ -1064,8 +1068,8 @@ is not read-only."
                                  posn))
                     ;; Look for the command bound to this event.
                     (command (key-binding (if prefix
-                                                 (vector prefix
-                                                         (car event))
+                                              (vector prefix
+                                                      (car event))
                                             (vector (car event)))
                                           t nil posn)))
                (deactivate-mark)
@@ -1154,7 +1158,28 @@ is not read-only."
            ;; took place.
            (throw 'input-event
                   (list 'down-mouse-1
-                        (nth 4 touch-screen-current-tool)))))))
+                        (nth 4 touch-screen-current-tool))))
+          ((or (eq what 'drag)
+               ;; Merely initiating a drag is sufficient to select a
+               ;; word if word selection is enabled.
+               (eq what 'held))
+           ;; Display the on screen keyboard if the region is now
+           ;; active.  Check this within the window where the tool was
+           ;; first place.
+           (setq window (nth 1 touch-screen-current-tool))
+           (when window
+             (with-selected-window window
+               (when (and (region-active-p)
+                          (not buffer-read-only))
+                 ;; Once the on-screen keyboard has been opened, add
+                 ;; `touch-screen-window-selection-changed' as a window
+                 ;; selection change function This then prevents it from
+                 ;; being hidden after exiting the minibuffer.
+                 (progn
+                   (add-hook 'window-selection-change-functions
+                             #'touch-screen-window-selection-changed)
+                   (frame-toggle-on-screen-keyboard (selected-frame)
+                                                    nil)))))))))
 
 (defun touch-screen-handle-touch (event prefix &optional interactive)
   "Handle a single touch EVENT, and perform associated actions.
diff --git a/lisp/treesit.el b/lisp/treesit.el
index a9761dbb38d..d7032b16dab 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -92,6 +92,8 @@
 
 (declare-function treesit-available-p "treesit.c")
 
+(defvar treesit-thing-settings)
+
 ;;; Custom options
 
 ;; Tree-sitter always appear as treesit in symbols.
@@ -257,7 +259,7 @@ If INCLUDE-NODE is non-nil, return NODE if it satisfies 
PRED."
                             (treesit-node-parent node))
              then (treesit-node-parent cursor)
              while cursor
-             if (treesit-node-match-p cursor pred)
+             if (treesit-node-match-p cursor pred t)
              do (setq result cursor))
     result))
 
@@ -1799,6 +1801,8 @@ BACKWARD and ALL are the same as in 
`treesit-search-forward'."
       (goto-char current-pos)))
     node))
 
+(make-obsolete 'treesit-sexp-type-regexp "`treesit-sexp-type-regexp' will be 
removed in a few months, use `treesit-thing-settings' instead." "30.0.5")
+
 (defvar-local treesit-sexp-type-regexp nil
   "A regexp that matches the node type of sexp nodes.
 
@@ -1816,7 +1820,7 @@ like `forward-sexp' does.  If point is already at 
top-level,
 return nil without moving point."
   (interactive "^p")
   (let ((arg (or arg 1))
-        (pred treesit-sexp-type-regexp))
+        (pred (or treesit-sexp-type-regexp 'sexp)))
     (or (if (> arg 0)
             (treesit-end-of-thing pred (abs arg) 'restricted)
           (treesit-beginning-of-thing pred (abs arg) 'restricted))
@@ -1842,7 +1846,12 @@ its sibling node ARG nodes away.
 Return a pair of positions as described by
 `transpose-sexps-function' for use in `transpose-subr' and
 friends."
-  (let* ((parent (treesit-node-parent (treesit-node-at (point))))
+  ;; First arrive at the right level at where the node at point is
+  ;; considered a sexp. If sexp isn't defined, or we can't find any
+  ;; node that's a sexp, use the node at point.
+  (let* ((node (or (treesit-thing-at-point 'sexp 'nested)
+                   (treesit-node-at (point))))
+         (parent (treesit-node-parent node))
          (child (treesit-node-child parent 0 t)))
     (named-let loop ((prev child)
                      (next (treesit-node-next-sibling child t)))
@@ -1900,9 +1909,6 @@ for invalid node.
 
 This is used by `treesit-beginning-of-defun' and friends.")
 
-(defvar-local treesit-block-type-regexp nil
-  "Like `treesit-defun-type-regexp', but for blocks.")
-
 (defvar-local treesit-defun-tactic 'nested
   "Determines how does Emacs treat nested defuns.
 If the value is `top-level', Emacs only moves across top-level
@@ -1928,11 +1934,26 @@ nil.")
   "The delimiter used to connect several defun names.
 This is used in `treesit-add-log-current-defun'.")
 
-(defun treesit-beginning-of-thing (pred &optional arg tactic)
+(defun treesit-thing-definition (thing language)
+  "Return the predicate for THING if it's defined for LANGUAGE.
+A thing is considered defined if it has an entry in
+`treesit-thing-settings'.
+
+If LANGUAGE is nil, return the first definition for THING in
+`treesit-thing-settings'."
+  (if language
+      (car (alist-get thing (alist-get language
+                                       treesit-thing-settings)))
+    (car (alist-get thing (mapcan #'cdr treesit-thing-settings)))))
+
+(defalias 'treesit-thing-defined-p 'treesit-thing-definition
+  "Return non-nil if THING is defined.")
+
+(defun treesit-beginning-of-thing (thing &optional arg tactic)
   "Like `beginning-of-defun', but generalized into things.
 
-PRED is like `treesit-defun-type-regexp', ARG
-is the same as in `beginning-of-defun'.
+THING can be a thing defined in `treesit-thing-settings', which see,
+or a predicate.  ARG is the same as in `beginning-of-defun'.
 
 TACTIC determines how does this function move between things.  It
 can be `nested', `top-level', `restricted', or nil.  `nested'
@@ -1947,15 +1968,15 @@ should there be one.  If omitted, TACTIC is considered 
to be
 Return non-nil if successfully moved, nil otherwise."
   (pcase-let* ((arg (or arg 1))
                (dest (treesit--navigate-thing
-                      (point) (- arg) 'beg pred tactic)))
+                      (point) (- arg) 'beg thing tactic)))
     (when dest
       (goto-char dest))))
 
-(defun treesit-end-of-thing (pred &optional arg tactic)
+(defun treesit-end-of-thing (thing &optional arg tactic)
   "Like `end-of-defun', but generalized into things.
 
-PRED is like `treesit-defun-type-regexp', ARG is the same as
-in `end-of-defun'.
+THING can be a thing defined in `treesit-thing-settings', which
+see, or a predicate.  ARG is the same as in `end-of-defun'.
 
 TACTIC determines how does this function move between things.  It
 can be `nested', `top-level', `restricted', or nil.  `nested'
@@ -1970,7 +1991,7 @@ should there be one.  If omitted, TACTIC is considered to 
be
 Return non-nil if successfully moved, nil otherwise."
   (pcase-let* ((arg (or arg 1))
                (dest (treesit--navigate-thing
-                      (point) arg 'end pred tactic)))
+                      (point) arg 'end thing tactic)))
     (when dest
       (goto-char dest))))
 
@@ -1984,19 +2005,21 @@ If search is successful, return t, otherwise return nil.
 
 This is a tree-sitter equivalent of `beginning-of-defun'.
 Behavior of this function depends on `treesit-defun-type-regexp'
-and `treesit-defun-skipper'."
+and `treesit-defun-skipper'.  If `treesit-defun-type-regexp' is
+not set, Emacs also looks for definition of defun in
+`treesit-thing-settings'."
   (interactive "^p")
   (or (not (eq this-command 'treesit-beginning-of-defun))
       (eq last-command 'treesit-beginning-of-defun)
       (and transient-mark-mode mark-active)
       (push-mark))
   (let ((orig-point (point))
-        (success nil))
+        (success nil)
+        (pred (or treesit-defun-type-regexp 'defun)))
     (catch 'done
       (dotimes (_ 2)
 
-        (when (treesit-beginning-of-thing
-               treesit-defun-type-regexp arg treesit-defun-tactic)
+        (when (treesit-beginning-of-thing pred arg treesit-defun-tactic)
           (when treesit-defun-skipper
             (funcall treesit-defun-skipper)
             (setq success t)))
@@ -2017,9 +2040,12 @@ Negative argument -N means move back to Nth preceding 
end of defun.
 
 This is a tree-sitter equivalent of `end-of-defun'.  Behavior of
 this function depends on `treesit-defun-type-regexp' and
-`treesit-defun-skipper'."
+`treesit-defun-skipper'.  If `treesit-defun-type-regexp' is not
+set, Emacs also looks for definition of defun in
+`treesit-thing-settings'."
   (interactive "^p\nd")
-  (let ((orig-point (point)))
+  (let ((orig-point (point))
+        (pred (or treesit-defun-type-regexp 'defun)))
     (if (or (null arg) (= arg 0)) (setq arg 1))
     (or (not (eq this-command 'treesit-end-of-defun))
         (eq last-command 'treesit-end-of-defun)
@@ -2028,8 +2054,7 @@ this function depends on `treesit-defun-type-regexp' and
     (catch 'done
       (dotimes (_ 2) ; Not making progress is better than infloop.
 
-        (when (treesit-end-of-thing
-               treesit-defun-type-regexp arg treesit-defun-tactic)
+        (when (treesit-end-of-thing pred arg treesit-defun-tactic)
           (when treesit-defun-skipper
             (funcall treesit-defun-skipper)))
 
@@ -2041,6 +2066,8 @@ this function depends on `treesit-defun-type-regexp' and
             (throw 'done nil)
           (setq arg (if (> arg 0) (1+ arg) (1- arg))))))))
 
+(make-obsolete 'treesit-text-type-regexp "`treesit-text-type-regexp' will be 
removed in a few months, use `treesit-thing-settings' instead." "30.0.5")
+
 (defvar-local treesit-text-type-regexp "\\`comment\\'"
   "A regexp that matches the node type of textual nodes.
 
@@ -2050,6 +2077,8 @@ comments and multiline string literals.  For example,
 \"text_block\" in the case of a string.  This is used by
 `prog-fill-reindent-defun' and friends.")
 
+(make-obsolete 'treesit-sentence-type-regexp "`treesit-sentence-type-regexp' 
will be removed in a few months, use `treesit-thing-settings' instead." 
"30.0.5")
+
 (defvar-local treesit-sentence-type-regexp nil
   "A regexp that matches the node type of sentence nodes.
 
@@ -2059,21 +2088,21 @@ smaller in scope than defuns.  This is used by
 `treesit-forward-sentence' and friends.")
 
 (defun treesit-forward-sentence (&optional arg)
-  "Tree-sitter `forward-sentence-function' function.
+  "Tree-sitter `forward-sentence-function' implementation.
 
 ARG is the same as in `forward-sentence'.
 
-If inside comment or other nodes described in
-`treesit-sentence-type-regexp', use
-`forward-sentence-default-function', else move across nodes as
-described by `treesit-sentence-type-regexp'."
-  (if (string-match-p
-       treesit-text-type-regexp
-       (treesit-node-type (treesit-node-at (point))))
+If point is inside a text environment, go forward a prose
+sentence using `forward-sentence-default-function'.  If point is
+inside code, go forward a source code sentence.
+
+What constitutes as text and source code sentence is determined
+by `text' and `sentence' in `treesit-thing-settings'."
+  (if (treesit-node-match-p (treesit-node-at (point)) 'text t)
       (funcall #'forward-sentence-default-function arg)
     (funcall
      (if (> arg 0) #'treesit-end-of-thing #'treesit-beginning-of-thing)
-     treesit-sentence-type-regexp (abs arg))))
+     'sentence (abs arg))))
 
 (defun treesit-default-defun-skipper ()
   "Skips spaces after navigating a defun.
@@ -2103,7 +2132,7 @@ the current line if the beginning of the defun is 
indented."
 ;; parent:
 ;; 1. node covers pos
 ;; 2. smallest such node
-(defun treesit--things-around (pos pred)
+(defun treesit--things-around (pos thing)
   "Return the previous, next, and parent thing around POS.
 
 Return a list of (PREV NEXT PARENT), where PREV and NEXT are
@@ -2111,8 +2140,8 @@ previous and next sibling things around POS, and PARENT 
is the
 parent thing surrounding POS.  All of three could be nil if no
 sound things exists.
 
-PRED can be a regexp, a predicate function, and more.  See
-`treesit-thing-settings' for details."
+THING should be a thing defined in `treesit-thing-settings',
+which see; it can also be a predicate."
   (let* ((node (treesit-node-at pos))
          (result (list nil nil nil)))
     ;; 1. Find previous and next sibling defuns.
@@ -2135,7 +2164,7 @@ PRED can be a regexp, a predicate function, and more.  See
      when node
      do (let ((cursor node)
               (iter-pred (lambda (node)
-                           (and (treesit-node-match-p node pred)
+                           (and (treesit-node-match-p node thing t)
                                 (funcall pos-pred node)))))
           ;; Find the node just before/after POS to start searching.
           (save-excursion
@@ -2149,11 +2178,11 @@ PRED can be a regexp, a predicate function, and more.  
See
             (setf (nth idx result)
                   (treesit-node-top-level cursor iter-pred t))
             (setq cursor (treesit-search-forward
-                          cursor pred backward backward)))))
+                          cursor thing backward backward)))))
     ;; 2. Find the parent defun.
     (let ((cursor (or (nth 0 result) (nth 1 result) node))
           (iter-pred (lambda (node)
-                       (and (treesit-node-match-p node pred)
+                       (and (treesit-node-match-p node thing t)
                             (not (treesit-node-eq node (nth 0 result)))
                             (not (treesit-node-eq node (nth 1 result)))
                             (< (treesit-node-start node)
@@ -2190,7 +2219,7 @@ PRED can be a regexp, a predicate function, and more.  See
 ;;    -> Obviously we don't want to go to parent's end, instead, we
 ;;       want to go to parent's prev-sibling's end.  Again, we recurse
 ;;       in the function to do that.
-(defun treesit--navigate-thing (pos arg side pred &optional tactic recursing)
+(defun treesit--navigate-thing (pos arg side thing &optional tactic recursing)
   "Navigate thing ARG steps from POS.
 
 If ARG is positive, move forward that many steps, if negative,
@@ -2201,7 +2230,7 @@ This function doesn't actually move point, it just 
returns the
 position it would move to.  If there aren't enough things to move
 across, return nil.
 
-PRED can be a regexp, a predicate function, and more.  See
+THING can be a regexp, a predicate function, and more.  See
 `treesit-thing-settings' for details.
 
 TACTIC determines how does this function move between things.  It
@@ -2231,13 +2260,13 @@ function is called recursively."
       (while (> counter 0)
         (pcase-let
             ((`(,prev ,next ,parent)
-              (treesit--things-around pos pred)))
+              (treesit--things-around pos thing)))
           ;; When PARENT is nil, nested and top-level are the same, if
           ;; there is a PARENT, make PARENT to be the top-level parent
           ;; and pretend there is no nested PREV and NEXT.
           (when (and (eq tactic 'top-level)
                      parent)
-            (setq parent (treesit-node-top-level parent pred t)
+            (setq parent (treesit-node-top-level parent thing t)
                   prev nil
                   next nil))
           ;; If TACTIC is `restricted', the implementation is very simple.
@@ -2269,7 +2298,7 @@ function is called recursively."
                     ;; the end of next before recurring.)
                     (setq pos (or (treesit--navigate-thing
                                    (treesit-node-end (or next parent))
-                                   1 'beg pred tactic t)
+                                   1 'beg thing tactic t)
                                   (throw 'term nil)))
                   ;; Normal case.
                   (setq pos (funcall advance (or next parent))))
@@ -2281,7 +2310,7 @@ function is called recursively."
                   ;; Special case: go to prev end-of-defun.
                   (setq pos (or (treesit--navigate-thing
                                  (treesit-node-start (or prev parent))
-                                 -1 'end pred tactic t)
+                                 -1 'end thing tactic t)
                                 (throw 'term nil)))
                 ;; Normal case.
                 (setq pos (funcall advance (or prev parent))))))
@@ -2291,17 +2320,17 @@ function is called recursively."
     (if (eq counter 0) pos nil)))
 
 ;; TODO: In corporate into thing-at-point.
-(defun treesit-thing-at-point (pred tactic)
+(defun treesit-thing-at-point (thing tactic)
   "Return the thing node at point or nil if none is found.
 
-\"Thing\" is defined by PRED, which can be a regexp, a
+\"Thing\" is defined by THING, which can be a regexp, a
 predication function, and more, see `treesit-thing-settings'
 for details.
 
 Return the top-level defun if TACTIC is `top-level', return the
 immediate parent thing if TACTIC is `nested'."
   (pcase-let* ((`(,_ ,next ,parent)
-                (treesit--things-around (point) pred))
+                (treesit--things-around (point) thing))
                ;; If point is at the beginning of a thing, we
                ;; prioritize that thing over the parent in nested
                ;; mode.
@@ -2309,7 +2338,7 @@ immediate parent thing if TACTIC is `nested'."
                               next)
                          parent)))
     (if (eq tactic 'top-level)
-        (treesit-node-top-level node pred t)
+        (treesit-node-top-level node thing t)
       node)))
 
 (defun treesit-defun-at-point ()
@@ -2319,10 +2348,11 @@ Respects `treesit-defun-tactic': return the top-level 
defun if it
 is `top-level', return the immediate parent defun if it is
 `nested'.
 
-Return nil if `treesit-defun-type-regexp' is not set."
-  (when treesit-defun-type-regexp
+Return nil if `treesit-defun-type-regexp' isn't set and `defun'
+isn't defined in `treesit-thing-settings'."
+  (when (or treesit-defun-type-regexp (treesit-thing-defined-p 'defun))
     (treesit-thing-at-point
-     treesit-defun-type-regexp treesit-defun-tactic)))
+     (or treesit-defun-type-regexp 'defun) treesit-defun-tactic)))
 
 (defun treesit-defun-name (node)
   "Return the defun name of NODE.
@@ -2495,14 +2525,18 @@ and enable `font-lock-mode'.
 
 If `treesit-simple-indent-rules' is non-nil, set up indentation.
 
-If `treesit-defun-type-regexp' is non-nil, set up
-`beginning-of-defun-function' and `end-of-defun-function'.
+If `treesit-defun-type-regexp' is non-nil or `defun' is defined
+in `treesit-thing-settings', set up `beginning-of-defun-function'
+and `end-of-defun-function'.
 
 If `treesit-defun-name-function' is non-nil, set up
 `add-log-current-defun'.
 
 If `treesit-simple-imenu-settings' is non-nil, set up Imenu.
 
+If `sexp', `sentence' are defined in `treesit-thing-settings',
+enable tree-sitter navigation commands for them.
+
 Make sure necessary parsers are created for the current buffer
 before calling this function."
   ;; Font-lock.
@@ -2526,7 +2560,8 @@ before calling this function."
     (setq-local indent-line-function #'treesit-indent)
     (setq-local indent-region-function #'treesit-indent-region))
   ;; Navigation.
-  (when treesit-defun-type-regexp
+  (when (or treesit-defun-type-regexp
+            (treesit-thing-defined-p 'defun nil))
     (keymap-set (current-local-map) "<remap> <beginning-of-defun>"
                 #'treesit-beginning-of-defun)
     (keymap-set (current-local-map) "<remap> <end-of-defun>"
@@ -2545,10 +2580,11 @@ before calling this function."
     (setq-local add-log-current-defun-function
                 #'treesit-add-log-current-defun))
 
-  (when treesit-sexp-type-regexp
-    (setq-local forward-sexp-function #'treesit-forward-sexp))
-  (setq-local transpose-sexps-function #'treesit-transpose-sexps)
-  (when treesit-sentence-type-regexp
+  (when (treesit-thing-defined-p 'sexp nil)
+    (setq-local forward-sexp-function #'treesit-forward-sexp)
+    (setq-local transpose-sexps-function #'treesit-transpose-sexps))
+
+  (when (treesit-thing-defined-p 'sentence nil)
     (setq-local forward-sentence-function #'treesit-forward-sentence))
 
   ;; Imenu.
@@ -2605,7 +2641,8 @@ in `treesit-parser-list'."
                         'bold nil))
         name
         (if (treesit-node-check node 'named) ")" "\""))))
-    (setq treesit--inspect-name name)
+    ;; Escape the percent character for mode-line. (Bug#65540)
+    (setq treesit--inspect-name (string-replace "%" "%%" name))
     (force-mode-line-update)
     (when arg
       (if node-list
diff --git a/lisp/url/url-gw.el b/lisp/url/url-gw.el
index 4d7297f6f2e..568ce8679f5 100644
--- a/lisp/url/url-gw.el
+++ b/lisp/url/url-gw.el
@@ -1,6 +1,6 @@
 ;;; url-gw.el --- Gateway munging for URL loading  -*- lexical-binding: t; -*-
 
-;; Copyright (C) 1997-1998, 2004-2023 Free Software Foundation, Inc.
+;; Copyright (C) 1997-2023 Free Software Foundation, Inc.
 
 ;; Author: Bill Perry <wmperry@gnu.org>
 ;; Maintainer: emacs-devel@gnu.org
@@ -97,21 +97,27 @@ This list will be executed as a command after logging in 
via telnet."
 
 (defcustom url-gateway-broken-resolution nil
   "Whether to use nslookup to resolve hostnames.
-This should be used when your version of Emacs cannot correctly use DNS,
-but your machine can.  This usually happens if you are running a statically
-linked Emacs under SunOS 4.x."
+This should be used when your version of Emacs cannot correctly
+use DNS, but your machine can.
+
+This used to happen on SunOS 4.x and Ultrix when Emacs was linked
+statically, and also was not linked with the resolver libraries.
+Those systems are no longer supported by Emacs."
   :type 'boolean
   :group 'url-gateway)
+(make-obsolete-variable 'url-gateway-broken-resolution nil "30.1")
 
 (defcustom url-gateway-nslookup-program "nslookup"
   "If non-nil then a string naming nslookup program."
   :type '(choice (const :tag "None" :value nil) string)
   :group 'url-gateway)
+(make-obsolete-variable 'url-gateway-nslookup-program nil "30.1")
 
 ;; Stolen from ange-ftp
 ;;;###autoload
 (defun url-gateway-nslookup-host (host)
   "Attempt to resolve the given HOST using nslookup if possible."
+  (declare (obsolete nil "30.1"))
   (interactive "sHost:  ")
   (if url-gateway-nslookup-program
       (let ((proc (start-process " *nslookup*" " *nslookup*"
@@ -237,7 +243,8 @@ overriding the value of `url-gateway-method'."
 
       ;; If the user told us to do DNS for them, do it.
       (if url-gateway-broken-resolution
-         (setq host (url-gateway-nslookup-host host)))
+          (with-suppressed-warnings ((obsolete url-gateway-nslookup-host))
+            (setq host (url-gateway-nslookup-host host))))
 
       ;; This is a clean way to ensure the new process inherits the
       ;; right coding systems in both Emacs and XEmacs.
diff --git a/lisp/url/url-vars.el b/lisp/url/url-vars.el
index 7e2290217d0..ef4b8b2841b 100644
--- a/lisp/url/url-vars.el
+++ b/lisp/url/url-vars.el
@@ -331,7 +331,7 @@ undefined."
 (defcustom url-max-redirections 30
   "The maximum number of redirection requests to honor in a HTTP connection.
 A negative number means to honor an unlimited number of redirection requests."
-  :type 'natnum
+  :type 'integer
   :group 'url)
 
 (defcustom url-confirmation-func 'y-or-n-p
diff --git a/lisp/vc/ediff-util.el b/lisp/vc/ediff-util.el
index c4ebe20d7e4..00200f1d1da 100644
--- a/lisp/vc/ediff-util.el
+++ b/lisp/vc/ediff-util.el
@@ -3138,16 +3138,15 @@ Hit \\[ediff-recenter] to reset the windows afterward."
                   ;; e.g., if file name ends with .Z or .gz
                    ;; This is needed so that patches produced by ediff will
                   ;; have more meaningful names
-                  (ediff-make-empty-tmp-file short-f))
+                   (make-temp-file short-f))
                  (prefix
                   ;; Prefix is most often the same as the file name for the
-                  ;; variant.  Here we are trying to use the original file
-                  ;; name but in the temp directory.
-                  (ediff-make-empty-tmp-file f 'keep-name))
+                   ;; variant.
+                   (make-temp-file f))
                  (t
                   ;; If don't care about name, add some random stuff
                   ;; to proposed file name.
-                  (ediff-make-empty-tmp-file short-f))))
+                   (make-temp-file short-f))))
 
     ;; create the file
     (ediff-with-current-buffer buff
@@ -3159,28 +3158,6 @@ Hit \\[ediff-recenter] to reset the windows afterward."
       (set-file-modes f ediff-temp-file-mode)
       (expand-file-name f))))
 
-;; Create a temporary file.
-;; The returned file name (created by appending some random characters at the
-;; end of PROPOSED-NAME is guaranteed to point to a newly created empty file.
-;; This is a replacement for make-temp-name, which eliminates a security hole.
-;; If KEEP-PROPOSED-NAME isn't nil, try to keep PROPOSED-NAME, unless such file
-;; already exists.
-;; It is a modified version of make-temp-file in emacs 20.5
-(defun ediff-make-empty-tmp-file (proposed-name &optional keep-proposed-name)
-  (let ((file proposed-name))
-    (while (condition-case ()
-               (progn
-                (if (or (file-exists-p file) (not keep-proposed-name))
-                    (setq file (make-temp-name proposed-name)))
-                 (write-region "" nil file nil 'silent nil 'excl)
-                 nil)
-            (file-already-exists t))
-      ;; the file was somehow created by someone else between
-      ;; `make-temp-name' and `write-region', let's try again.
-      nil)
-    file))
-
-
 ;; Make sure the current buffer (for a file) has the same contents as the
 ;; file on disk, and attempt to remedy the situation if not.
 ;; Signal an error if we can't make them the same, or the user doesn't want
@@ -4144,6 +4121,10 @@ Mail anyway? (y or n) ")
 (define-obsolete-function-alias 'ediff-intersection #'seq-intersection "28.1")
 (define-obsolete-function-alias 'ediff-set-difference #'seq-difference "28.1")
 
+(defun ediff-make-empty-tmp-file (prefix &optional _ignored)
+  (declare (obsolete make-temp-file "30.1"))
+  (make-temp-file prefix))
+
 (run-hooks 'ediff-load-hook)
 
 ;;; ediff-util.el ends here
diff --git a/lisp/vc/emerge.el b/lisp/vc/emerge.el
index e95742b304a..5328ebc73ad 100644
--- a/lisp/vc/emerge.el
+++ b/lisp/vc/emerge.el
@@ -877,8 +877,8 @@ This is *not* a user option, since Emerge uses it for its 
own processing.")
 (defun emerge-buffers (buffer-A buffer-B &optional startup-hooks quit-hooks)
   "Run Emerge on two buffers BUFFER-A and BUFFER-B."
   (interactive "bBuffer A to merge: \nbBuffer B to merge: ")
-  (let ((emerge-file-A (emerge-make-temp-file "A"))
-       (emerge-file-B (emerge-make-temp-file "B")))
+  (let ((emerge-file-A (make-temp-file "emerge-A"))
+        (emerge-file-B (make-temp-file "emerge-B")))
     (with-current-buffer
      buffer-A
      (write-region (point-min) (point-max) emerge-file-A nil 'no-message))
@@ -901,9 +901,9 @@ This is *not* a user option, since Emerge uses it for its 
own processing.")
   "Run Emerge on two buffers, giving another buffer as the ancestor."
   (interactive
    "bBuffer A to merge: \nbBuffer B to merge: \nbAncestor buffer: ")
-  (let ((emerge-file-A (emerge-make-temp-file "A"))
-       (emerge-file-B (emerge-make-temp-file "B"))
-       (emerge-file-ancestor (emerge-make-temp-file "anc")))
+  (let ((emerge-file-A (make-temp-file "emerge-A"))
+        (emerge-file-B (make-temp-file "emerge-B"))
+        (emerge-file-ancestor (make-temp-file "emerge-ancestor")))
     (with-current-buffer
      buffer-A
      (write-region (point-min) (point-max) emerge-file-A nil 'no-message))
@@ -1039,8 +1039,8 @@ This is *not* a user option, since Emerge uses it for its 
own processing.")
                                   startup-hooks quit-hooks _output-file)
   (let ((buffer-A (get-buffer-create (format "%s,%s" file revision-A)))
        (buffer-B (get-buffer-create (format "%s,%s" file revision-B)))
-       (emerge-file-A (emerge-make-temp-file "A"))
-       (emerge-file-B (emerge-make-temp-file "B")))
+        (emerge-file-A (make-temp-file "emerge-A"))
+        (emerge-file-B (make-temp-file "emerge-B")))
     ;; Get the revisions into buffers
     (with-current-buffer
      buffer-A
@@ -1076,9 +1076,9 @@ This is *not* a user option, since Emerge uses it for its 
own processing.")
   (let ((buffer-A (get-buffer-create (format "%s,%s" file revision-A)))
        (buffer-B (get-buffer-create (format "%s,%s" file revision-B)))
        (buffer-ancestor (get-buffer-create (format "%s,%s" file ancestor)))
-       (emerge-file-A (emerge-make-temp-file "A"))
-       (emerge-file-B (emerge-make-temp-file "B"))
-       (emerge-ancestor (emerge-make-temp-file "ancestor")))
+        (emerge-file-A (make-temp-file "emerge-A"))
+        (emerge-file-B (make-temp-file "emerge-B"))
+        (emerge-ancestor (make-temp-file "emerge-ancestor")))
     ;; Get the revisions into buffers
     (with-current-buffer
      buffer-A
@@ -2851,14 +2851,6 @@ Otherwise, signal an error."
     (setq vars (cdr vars))
     (setq values (cdr values))))
 
-;; When the pointless option emerge-temp-file-prefix goes,
-;; make this function obsolete too, and just use make-temp-file.
-(defun emerge-make-temp-file (prefix)
-  "Make a private temporary file based on PREFIX.
-This is named by concatenating `emerge-temp-file-prefix' with
-PREFIX."
-  (make-temp-file (concat emerge-temp-file-prefix prefix)))
-
 ;;; Functions that query the user before he can write out the current buffer.
 
 (defun emerge-query-write-file ()
@@ -3062,6 +3054,8 @@ See also `auto-save-file-name-p'."
   :type '(choice (const nil) regexp))
 (make-obsolete-variable 'emerge-metachars nil "26.1")
 
+(define-obsolete-function-alias 'emerge-make-temp-file #'make-temp-file "30.1")
+
 (provide 'emerge)
 
 ;;; emerge.el ends here
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index c689eec444b..5c21a5b884e 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -122,7 +122,10 @@ If nil, use the value of `vc-diff-switches'.  If t, use no 
switches."
 
 (defcustom vc-git-annotate-switches nil
   "String or list of strings specifying switches for Git blame under VC.
-If nil, use the value of `vc-annotate-switches'.  If t, use no switches."
+If nil, use the value of `vc-annotate-switches'.  If t, use no switches.
+
+Tip: Set this to \"-w\" to make Git blame ignore whitespace when
+comparing changes.  See Man page `git-blame' for more."
   :type '(choice (const :tag "Unspecified" nil)
                 (const :tag "None" t)
                 (string :tag "Argument String")
@@ -1058,7 +1061,8 @@ It is based on `log-edit-mode', and has Git-specific 
extensions."
           ;; might not support the non-ASCII characters in the log
           ;; message.  Handle also remote files.
           (if (eq system-type 'windows-nt)
-              (let ((default-directory (file-name-directory file1)))
+              (let ((default-directory (or (file-name-directory file1)
+                                           default-directory)))
                 (make-nearby-temp-file "git-msg"))))
          to-stash)
     (when vc-git-patch-string
@@ -1120,7 +1124,15 @@ It is based on `log-edit-mode', and has Git-specific 
extensions."
                     (t (push file-name to-stash)))
               (setq pos (point))))))
       (unless (string-empty-p vc-git-patch-string)
-        (let ((patch-file (make-nearby-temp-file "git-patch")))
+        (let ((patch-file (make-nearby-temp-file "git-patch"))
+              ;; Temporarily countermand the let-binding at the
+              ;; beginning of this function.
+              (coding-system-for-write
+               (coding-system-change-eol-conversion
+                ;; On DOS/Windows, it is important for the patch file
+                ;; to have the Unix EOL format, because Git expects
+                ;; that, even on Windows.
+                (or pcsw vc-git-commits-coding-system) 'unix)))
           (with-temp-file patch-file
             (insert vc-git-patch-string))
           (unwind-protect
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index b62420393aa..c3e563a1f10 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -249,7 +249,10 @@ If `ask', you will be prompted for a branch type."
                     (error nil)))))))
     (when (and (eq 0 status)
               (> (length out) 0)
-              (null (string-match ".*: No such file or directory$" out)))
+                         ;; Posix
+              (null (or (string-match ".*: No such file or directory$" out)
+                         ;; MS-Windows
+                         (string-match ".*: The system cannot find the file 
specified$" out))))
       (let ((state (aref out 0)))
        (cond
         ((eq state ?=) 'up-to-date)
diff --git a/lisp/vc/vc-hooks.el b/lisp/vc/vc-hooks.el
index e75165ea2e9..a4de0a6e791 100644
--- a/lisp/vc/vc-hooks.el
+++ b/lisp/vc/vc-hooks.el
@@ -87,6 +87,11 @@
   "Face for VC modeline state when the file is edited."
   :version "25.1")
 
+(defface vc-ignored-state
+  '((default :inherit vc-state-base))
+  "Face for VC modeline state when the file is registered, but ignored."
+  :version "30.1")
+
 ;; Customization Variables (the rest is in vc.el)
 
 (defcustom vc-ignore-dir-regexp
@@ -743,6 +748,10 @@ This function assumes that the file is registered."
             (setq state-echo "File tracked by the VC system, but missing from 
the file system")
            (setq face 'vc-missing-state)
             (concat backend-name "?" rev))
+           ((eq state 'ignored)
+            (setq state-echo "File tracked by the VC system, but ignored")
+            (setq face 'vc-ignored-state)
+            (concat backend-name "!" rev))
           (t
            ;; Not just for the 'edited state, but also a fallback
            ;; for all other states.  Think about different symbols
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index be7fa46c28e..2f4b028bb4a 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -1883,7 +1883,9 @@ in the output buffer."
     (vc-run-delayed (vc-diff-finish (current-buffer) nil))))
 
 (defun vc-diff-internal (async vc-fileset rev1 rev2 &optional verbose buffer)
-  "Report diffs between two revisions of a fileset.
+  "Report diffs between revisions REV1 and REV2 of a fileset in VC-FILESET.
+ASYNC non-nil means run the backend's commands asynchronously if possible.
+VC-FILESET should have the format described in `vc-deduce-fileset'.
 Output goes to the buffer BUFFER, which defaults to *vc-diff*.
 BUFFER, if non-nil, should be a buffer or a buffer name.
 Return t if the buffer had changes, nil otherwise."
@@ -1899,15 +1901,26 @@ Return t if the buffer had changes, nil otherwise."
         ;; but the only way to set it for each file included would
         ;; be to call the back end separately for each file.
         (coding-system-for-read
-         (if files (vc-coding-system-for-diff (car files)) 'undecided))
+          ;; Force the EOL conversion to be -unix, in case the files
+          ;; to be compared have DOS EOLs.  In that case, EOL
+          ;; conversion will produce a patch file that will either
+          ;; fail to apply, or will change the EOL format of some of
+          ;; the lines in the patched file.
+          (coding-system-change-eol-conversion
+          (if files (vc-coding-system-for-diff (car files)) 'undecided)
+           'unix))
          (orig-diff-buffer-clone
           (if revert-buffer-in-progress-p
               (clone-buffer
                (generate-new-buffer-name " *vc-diff-clone*") nil))))
     ;; On MS-Windows and MS-DOS, Diff is likely to produce DOS-style
     ;; EOLs, which will look ugly if (car files) happens to have Unix
-    ;; EOLs.
-    (if (memq system-type '(windows-nt ms-dos))
+    ;; EOLs.  But for Git, we must force Unix EOLs in the diffs, since
+    ;; Git always produces Unix EOLs in the parts that didn't come
+    ;; from the file, and wants to see any CR characters when applying
+    ;; patches.
+    (if (and (memq system-type '(windows-nt ms-dos))
+             (not (eq (car vc-fileset) 'Git)))
        (setq coding-system-for-read
              (coding-system-change-eol-conversion coding-system-for-read
                                                   'dos)))
diff --git a/lisp/wid-edit.el b/lisp/wid-edit.el
index ae060c92d0e..d18d721f7ed 100644
--- a/lisp/wid-edit.el
+++ b/lisp/wid-edit.el
@@ -282,16 +282,20 @@ The user is asked to choose between each NAME from ITEMS.
 If ITEMS has simple item definitions, then this function returns the VALUE of
 the chosen element.  If ITEMS is a keymap, then the return value is the symbol
 in the key vector, as in the argument of `define-key'."
-  ;; Apply quote substitution to customize choice menu item text,
-  ;; whether it occurs in a widget buffer or in a popup menu.
+  ;; Apply substitution to choice menu title and item text, whether it
+  ;; occurs in a widget buffer or in a popup menu.
   (let ((items (mapc (lambda (x)
-                       (when (consp x)
-                         (dotimes (i (1- (length x)))
-                           (when (stringp (nth i x))
-                             (setcar (nthcdr i x)
-                                     (substitute-command-keys
-                                      (car (nthcdr i x))))))))
-                    items)))
+                       (if (proper-list-p x)
+                           (dotimes (i (1- (length x)))
+                             (when (stringp (nth i x))
+                               (setcar (nthcdr i x)
+                                       (substitute-command-keys
+                                        (car (nthcdr i x))))))
+                         ;; ITEMS has simple item definitions.
+                         (when (and (consp x) (stringp (car x)))
+                           (setcar x (substitute-command-keys (car x))))))
+                    items))
+        (title (substitute-command-keys title)))
     (cond ((and (< (length items) widget-menu-max-size)
                event (display-popup-menus-p))
           ;; Mouse click.
diff --git a/src/android.c b/src/android.c
index ed304baf0e6..b501a66b25d 100644
--- a/src/android.c
+++ b/src/android.c
@@ -18,6 +18,7 @@ You should have received a copy of the GNU General Public 
License
 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
+
 #include <allocator.h>
 #include <assert.h>
 #include <careadlinkat.h>
@@ -31,12 +32,15 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <pthread.h>
 #include <semaphore.h>
 #include <signal.h>
+#include <stat-time.h>
 #include <stdckdint.h>
 #include <string.h>
-#include <sys/param.h>
 #include <timespec.h>
 #include <unistd.h>
 
+#include <sys/param.h>
+#include <sys/stat.h>
+
 /* Old NDK versions lack MIN and MAX.  */
 #include <minmax.h>
 
@@ -47,6 +51,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "blockinput.h"
 #include "coding.h"
 #include "epaths.h"
+#include "systime.h"
 
 /* Whether or not Emacs is running inside the application process and
    Android windowing should be enabled.  */
@@ -187,6 +192,10 @@ static struct android_emacs_window window_class;
 /* Various methods associated with the EmacsCursor class.  */
 static struct android_emacs_cursor cursor_class;
 
+/* The time at which Emacs was installed, which also supplies the
+   mtime of asset files.  */
+struct timespec emacs_installation_time;
+
 /* The last event serial used.  This is a 32 bit value, but it is
    stored in unsigned long to be consistent with X.  */
 unsigned int event_serial;
@@ -824,22 +833,18 @@ android_user_full_name (struct passwd *pw)
     return (char *) "Android user";
 
   return pw->pw_gecos;
-#else
+#else /* !HAVE_STRUCT_PASSWD_PW_GECOS */
   return "Android user";
-#endif
+#endif /* HAVE_STRUCT_PASSWD_PW_GECOS */
 }
 
 
 
-/* Determine whether or not the specified file NAME describes a file
-   in the directory DIR, which should be an absolute file name.  NAME
-   must be in canonical form.
+/* Return whether or not the specified file NAME designates a file in
+   the directory DIR, which should be an absolute file name.  NAME
+   must be in canonical form.  */
 
-   Value is NULL if not.  Otherwise, it is a pointer to the first
-   character in NAME after the part containing DIR and its trailing
-   directory separator.  */
-
-const char *
+bool
 android_is_special_directory (const char *name, const char *dir)
 {
   size_t len;
@@ -848,7 +853,7 @@ android_is_special_directory (const char *name, const char 
*dir)
 
   len = strlen (dir);
   if (strncmp (name, dir, len))
-    return NULL;
+    return false;
 
   /* Now see if the character of NAME after len is either a directory
      separator or a terminating NULL.  */
@@ -856,20 +861,13 @@ android_is_special_directory (const char *name, const 
char *dir)
   name += len;
   switch (*name)
     {
-    case '\0':
-      /* Return the empty string if this is the end of the file
-        name.  */
-      return name;
-
-    case '/':
-      /* Return NAME (with the separator removed) if it describes a
-        file.  */
-      return name + 1;
-
-    default:
-      /* The file name doesn't match.  */
-      return NULL;
+    case '\0': /* NAME is an exact match for DIR.  */
+    case '/':  /* NAME is a constituent of DIR.  */
+      return true;
     }
+
+  /* The file name doesn't match.  */
+  return false;
 }
 
 #if 0
@@ -1247,6 +1245,7 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject object,
   int pipefd[2];
   pthread_t thread;
   const char *java_string;
+  struct stat statb;
 
   /* Set the Android API level early, as it is used by
      `android_vfs_init'.  */
@@ -1341,13 +1340,24 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject 
object,
 
       android_class_path = strdup ((const char *) java_string);
 
-      if (!android_files_dir)
+      if (!android_class_path)
        emacs_abort ();
 
       (*env)->ReleaseStringUTFChars (env, (jstring) class_path,
                                     java_string);
     }
 
+  /* Derive the installation date from the modification time of the
+     file constitituing the class path.  */
+
+  emacs_installation_time = invalid_timespec ();
+
+  if (class_path)
+    {
+      if (!stat (android_class_path, &statb))
+       emacs_installation_time = get_stat_mtime (&statb);
+    }
+
   /* Calculate the site-lisp path.  */
 
   android_site_load_path = malloc (PATH_MAX + 1);
@@ -2267,6 +2277,12 @@ NATIVE_NAME (shouldForwardMultimediaButtons) (JNIEnv 
*env,
   return !android_pass_multimedia_buttons_to_system;
 }
 
+JNIEXPORT jboolean JNICALL
+NATIVE_NAME (shouldForwardCtrlSpace) (JNIEnv *env, jobject object)
+{
+  return !android_intercept_control_space;
+}
+
 JNIEXPORT void JNICALL
 NATIVE_NAME (blitRect) (JNIEnv *env, jobject object,
                        jobject src, jobject dest,
diff --git a/src/android.h b/src/android.h
index e865d7da665..d4605c11ad0 100644
--- a/src/android.h
+++ b/src/android.h
@@ -54,7 +54,7 @@ extern char *android_user_full_name (struct passwd *);
 /* File I/O operations.  Many of these are defined in
    androidvfs.c.  */
 
-extern const char *android_is_special_directory (const char *, const char *);
+extern bool android_is_special_directory (const char *, const char *);
 extern const char *android_get_home_directory (void);
 
 extern void android_vfs_init (JNIEnv *, jobject);
@@ -238,7 +238,7 @@ extern int android_rewrite_spawn_argv (const char ***);
 
 /* Define a substitute for use during Emacs compilation.  */
 
-#define android_is_special_directory(name, dir) ((const char *) NULL)
+#define android_is_special_directory(name, dir) (false)
 
 #endif /* !ANDROID_STUBIFY */
 
@@ -299,6 +299,10 @@ extern jobject emacs_service;
 /* Various methods associated with the EmacsService.  */
 extern struct android_emacs_service service_class;
 
+/* The time at which Emacs was installed, which also supplies the
+   mtime of asset files.  */
+extern struct timespec emacs_installation_time;
+
 #define ANDROID_DELETE_LOCAL_REF(ref)                          \
   ((*android_java_env)->DeleteLocalRef (android_java_env,      \
                                        (ref)))
diff --git a/src/androidfns.c b/src/androidfns.c
index 9e8372f524b..51421f0a68a 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -3205,6 +3205,19 @@ Note that if you set this, you will no longer be able to 
quit Emacs
 using the volume down button.  */);
   android_pass_multimedia_buttons_to_system = false;
 
+  DEFVAR_BOOL ("android-intercept-control-space",
+              android_intercept_control_space,
+    doc: /* Whether Emacs should intercept C-SPC.
+When this variable is set, Emacs intercepts C-SPC events as they are
+delivered to a frame before they are registered and filtered by the
+input method.
+
+For no apparent purpose, Android input methods customarily discard SPC
+events with the Ctrl modifier set without delivering them to Emacs
+afterwards, which is an impediment to typing key sequences
+incorporating such keys.  */);
+  android_intercept_control_space = true;
+
   DEFVAR_BOOL ("android-use-exec-loader", android_use_exec_loader,
     doc: /* Whether or not to bypass system restrictions on program execution.
 
diff --git a/src/androidvfs.c b/src/androidvfs.c
index d6b832d6caf..e8777892bd3 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -26,6 +26,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <errno.h>
 #include <minmax.h>
 #include <string.h>
+#include <systime.h>
 #include <semaphore.h>
 
 #include <sys/stat.h>
@@ -2058,7 +2059,7 @@ android_afs_stat (struct android_vnode *vnode, struct 
stat *statb)
       /* Concoct a nonexistent device and an inode number.  */
       statb->st_dev = -1;
       statb->st_ino = 0;
-      return 0;
+      goto set_file_times;
     }
 
   /* AASSET_MODE_STREAMING is fastest here.  */
@@ -2083,6 +2084,24 @@ android_afs_stat (struct android_vnode *vnode, struct 
stat *statb)
 
   /* Close the asset.  */
   AAsset_close (asset_desc);
+
+ set_file_times:
+
+  /* If the installation date can be ascertained, return that as the
+     file's modification time.  */
+
+  if (timespec_valid_p (emacs_installation_time))
+    {
+#ifdef STAT_TIMESPEC
+      STAT_TIMESPEC (statb, st_mtim) = emacs_installation_time;
+#else /* !STAT_TIMESPEC */
+      /* Headers supplied by the NDK r10b contain a `struct stat'
+        without POSIX fields for nano-second timestamps.  */
+      statb->st_mtime = emacs_installation_time.tv_sec;
+      statb->st_mtime_nsec = emacs_installation_time.tv_nsec;
+#endif /* STAT_TIMESPEC */
+    }
+
   return 0;
 }
 
diff --git a/src/chartab.c b/src/chartab.c
index 6f0bc28f31b..58bb1658504 100644
--- a/src/chartab.c
+++ b/src/chartab.c
@@ -580,7 +580,8 @@ DEFUN ("char-table-range", Fchar_table_range, 
Schar_table_range,
        2, 2, 0,
        doc: /* Return the value in CHAR-TABLE for a range of characters RANGE.
 RANGE should be nil (for the default value),
-a cons of character codes (for characters in the range), or a character code.  
*/)
+a cons of character codes (for characters in the range), or a character code.
+If RANGE is a cons (FROM . TO), the function returns the value for FROM.  */)
   (Lisp_Object char_table, Lisp_Object range)
 {
   Lisp_Object val;
diff --git a/src/data.c b/src/data.c
index 06b114afd0c..0907f911c5d 100644
--- a/src/data.c
+++ b/src/data.c
@@ -4381,8 +4381,6 @@ syms_of_data (void)
   defsubr (&Sbool_vector_count_consecutive);
   defsubr (&Sbool_vector_count_population);
 
-  set_symbol_function (Qwholenump, XSYMBOL (Qnatnump)->u.s.function);
-
   DEFVAR_LISP ("most-positive-fixnum", Vmost_positive_fixnum,
               doc: /* The greatest integer that is represented efficiently.
 This variable cannot be set; trying to do so will signal an error.  */);
diff --git a/src/fileio.c b/src/fileio.c
index 23e1a83d8bf..8919e08e1fd 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -4805,7 +4805,7 @@ by calling `format-decode', which see.  */)
 
        /* 'try' is reserved in some compilers (Microsoft C).  */
        ptrdiff_t trytry = min (gap_size, READ_BUF_SIZE);
-       if (!NILP (end))
+       if (seekable || !NILP (end))
          trytry = min (trytry, total - inserted);
 
        if (!seekable && NILP (end))
diff --git a/src/haiku_support.cc b/src/haiku_support.cc
index 12a84687180..3fc90385af3 100644
--- a/src/haiku_support.cc
+++ b/src/haiku_support.cc
@@ -741,8 +741,6 @@ public:
   EmacsWindow *parent;
   BRect pre_fullscreen_rect;
   BRect pre_zoom_rect;
-  int x_before_zoom;
-  int y_before_zoom;
   bool shown_flag;
   volatile bool was_shown_p;
   bool menu_bar_active_p;
@@ -760,8 +758,6 @@ public:
                            B_NORMAL_WINDOW_FEEL, 
B_NO_SERVER_SIDE_WINDOW_MODIFIERS),
                   subset_windows (NULL),
                   parent (NULL),
-                  x_before_zoom (INT_MIN),
-                  y_before_zoom (INT_MIN),
                   shown_flag (false),
                   was_shown_p (false),
                   menu_bar_active_p (false),
diff --git a/src/sfnt.c b/src/sfnt.c
index 87a11019b13..b66613eaa53 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -34,6 +34,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <unistd.h>
 #include <setjmp.h>
 #include <errno.h>
+#include <alloca.h>
 
 #ifdef HAVE_MMAP
 #include <sys/mman.h>
@@ -82,7 +83,7 @@ xrealloc (void *ptr, size_t size)
 static void
 xfree (void *ptr)
 {
-  return free (ptr);
+  free (ptr);
 }
 
 /* Use this for functions that are static while building in test mode,
@@ -5686,7 +5687,7 @@ sfnt_make_interpreter (struct sfnt_maxp_table *maxp,
   interpreter->run_hook = NULL;
   interpreter->push_hook = NULL;
   interpreter->pop_hook = NULL;
-#endif
+#endif /* TEST */
 
   /* Fill in pointers and default values.  */
   interpreter->max_stack_elements = maxp->max_stack_elements;
@@ -16305,7 +16306,7 @@ static struct sfnt_generic_test_args pushw_test_args =
 
 static struct sfnt_generic_test_args stack_overflow_test_args =
   {
-    (uint32_t[]) { },
+    NULL,
     0,
     true,
     0,
@@ -16313,8 +16314,7 @@ static struct sfnt_generic_test_args 
stack_overflow_test_args =
 
 static struct sfnt_generic_test_args stack_underflow_test_args =
   {
-    /* GCC BUG, this should be []! */
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     4,
@@ -16441,7 +16441,7 @@ static struct sfnt_generic_test_args jmpr_test_args =
 
 static struct sfnt_generic_test_args dup_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     5,
@@ -16457,7 +16457,7 @@ static struct sfnt_generic_test_args pop_test_args =
 
 static struct sfnt_generic_test_args clear_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     false,
     10,
@@ -16497,7 +16497,7 @@ static struct sfnt_generic_test_args mindex_test_args =
 
 static struct sfnt_generic_test_args raw_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     0,
@@ -16521,7 +16521,7 @@ static struct sfnt_generic_test_args call_test_args =
 
 static struct sfnt_generic_test_args fdef_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     4,
@@ -16529,7 +16529,7 @@ static struct sfnt_generic_test_args fdef_test_args =
 
 static struct sfnt_generic_test_args fdef_1_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     9,
@@ -16537,7 +16537,7 @@ static struct sfnt_generic_test_args fdef_1_test_args =
 
 static struct sfnt_generic_test_args endf_test_args =
   {
-    (uint32_t []) {  },
+    NULL,
     0,
     true,
     0,
@@ -16553,7 +16553,7 @@ static struct sfnt_generic_test_args ws_test_args =
 
 static struct sfnt_generic_test_args rs_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     2,
@@ -16593,7 +16593,7 @@ static struct sfnt_generic_test_args mps_test_args =
 
 static struct sfnt_generic_test_args debug_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     false,
     3,
@@ -16674,7 +16674,7 @@ static struct sfnt_generic_test_args if_test_args =
 
 static struct sfnt_generic_test_args eif_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     false,
     3,
@@ -16706,7 +16706,7 @@ static struct sfnt_generic_test_args not_test_args =
 
 static struct sfnt_generic_test_args sds_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     5,
@@ -16778,7 +16778,7 @@ static struct sfnt_generic_test_args ceiling_test_args =
 
 static struct sfnt_generic_test_args round_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     true,
     0,
@@ -16954,7 +16954,7 @@ static struct sfnt_generic_test_args rdtg_test_args =
 
 static struct sfnt_generic_test_args sangw_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     false,
     3,
@@ -16962,7 +16962,7 @@ static struct sfnt_generic_test_args sangw_test_args =
 
 static struct sfnt_generic_test_args aa_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     false,
     3,
@@ -17022,7 +17022,7 @@ static struct sfnt_generic_test_args min_test_args =
 
 static struct sfnt_generic_test_args scantype_test_args =
   {
-    (uint32_t []) { },
+    NULL,
     0,
     false,
     3,
diff --git a/src/treesit.c b/src/treesit.c
index f8673f8e895..995e7ea4bc8 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -80,6 +80,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #undef ts_tree_cursor_current_node
 #undef ts_tree_cursor_delete
 #undef ts_tree_cursor_goto_first_child
+#undef ts_tree_cursor_goto_first_child_for_byte
 #undef ts_tree_cursor_goto_next_sibling
 #undef ts_tree_cursor_goto_parent
 #undef ts_tree_cursor_new
@@ -147,6 +148,7 @@ DEF_DLL_FN (TSTreeCursor, ts_tree_cursor_copy, (const 
TSTreeCursor *));
 DEF_DLL_FN (TSNode, ts_tree_cursor_current_node, (const TSTreeCursor *));
 DEF_DLL_FN (void, ts_tree_cursor_delete, (const TSTreeCursor *));
 DEF_DLL_FN (bool, ts_tree_cursor_goto_first_child, (TSTreeCursor *));
+DEF_DLL_FN (int64_t, ts_tree_cursor_goto_first_child_for_byte, (TSTreeCursor 
*, uint32_t));
 DEF_DLL_FN (bool, ts_tree_cursor_goto_next_sibling, (TSTreeCursor *));
 DEF_DLL_FN (bool, ts_tree_cursor_goto_parent, (TSTreeCursor *));
 DEF_DLL_FN (TSTreeCursor, ts_tree_cursor_new, (TSNode));
@@ -210,6 +212,7 @@ init_treesit_functions (void)
   LOAD_DLL_FN (library, ts_tree_cursor_current_node);
   LOAD_DLL_FN (library, ts_tree_cursor_delete);
   LOAD_DLL_FN (library, ts_tree_cursor_goto_first_child);
+  LOAD_DLL_FN (library, ts_tree_cursor_goto_first_child_for_byte);
   LOAD_DLL_FN (library, ts_tree_cursor_goto_next_sibling);
   LOAD_DLL_FN (library, ts_tree_cursor_goto_parent);
   LOAD_DLL_FN (library, ts_tree_cursor_new);
@@ -267,6 +270,7 @@ init_treesit_functions (void)
 #define ts_tree_cursor_current_node fn_ts_tree_cursor_current_node
 #define ts_tree_cursor_delete fn_ts_tree_cursor_delete
 #define ts_tree_cursor_goto_first_child fn_ts_tree_cursor_goto_first_child
+#define ts_tree_cursor_goto_first_child_for_byte 
fn_ts_tree_cursor_goto_first_child_for_byte
 #define ts_tree_cursor_goto_next_sibling fn_ts_tree_cursor_goto_next_sibling
 #define ts_tree_cursor_goto_parent fn_ts_tree_cursor_goto_parent
 #define ts_tree_cursor_new fn_ts_tree_cursor_new
@@ -3027,7 +3031,8 @@ treesit_assume_true (bool val)
    limit.  */
 static bool
 treesit_cursor_helper_1 (TSTreeCursor *cursor, TSNode *target,
-                        uint32_t end_pos, ptrdiff_t limit)
+                        uint32_t start_pos, uint32_t end_pos,
+                        ptrdiff_t limit)
 {
   if (limit <= 0)
     return false;
@@ -3036,23 +3041,17 @@ treesit_cursor_helper_1 (TSTreeCursor *cursor, TSNode 
*target,
   if (ts_node_eq (cursor_node, *target))
     return true;
 
-  if (!ts_tree_cursor_goto_first_child (cursor))
+  if (ts_tree_cursor_goto_first_child_for_byte (cursor, start_pos) == -1)
     return false;
 
-  /* Skip nodes that definitely don't contain TARGET.  */
-  while (ts_node_end_byte (cursor_node) < end_pos)
-    {
-      if (!ts_tree_cursor_goto_next_sibling (cursor))
-       break;
-      cursor_node = ts_tree_cursor_current_node (cursor);
-    }
-
   /* Go through each sibling that could contain TARGET.  Because of
      missing nodes (their width is 0), there could be multiple
      siblings that could contain TARGET.  */
   while (ts_node_start_byte (cursor_node) <= end_pos)
     {
-      if (treesit_cursor_helper_1 (cursor, target, end_pos, limit - 1))
+      if (ts_node_end_byte (cursor_node) >= end_pos
+         && treesit_cursor_helper_1 (cursor, target, start_pos, end_pos,
+                                     limit - 1))
        return true;
 
       if (!ts_tree_cursor_goto_next_sibling (cursor))
@@ -3084,11 +3083,12 @@ treesit_cursor_helper_1 (TSTreeCursor *cursor, TSNode 
*target,
 static bool
 treesit_cursor_helper (TSTreeCursor *cursor, TSNode node, Lisp_Object parser)
 {
+  uint32_t start_pos = ts_node_start_byte (node);
   uint32_t end_pos = ts_node_end_byte (node);
   TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree);
   *cursor = ts_tree_cursor_new (root);
-  bool success = treesit_cursor_helper_1 (cursor, &node, end_pos,
-                                         TREESIT_RECURSION_LIMIT);
+  bool success = treesit_cursor_helper_1 (cursor, &node, start_pos,
+                                         end_pos, TREESIT_RECURSION_LIMIT);
   if (!success)
     ts_tree_cursor_delete (cursor);
   return success;
@@ -3220,7 +3220,7 @@ treesit_traverse_child_helper (TSTreeCursor *cursor,
 }
 
 /* Given a symbol THING, and a language symbol LANGUAGE, find the
-   corresponding predicate definition in treesit-things-settings.
+   corresponding predicate definition in treesit-thing-settings.
    Don't check for the type of THING and LANGUAGE.
 
    If there isn't one, return Qnil.  */
@@ -3246,13 +3246,15 @@ treesit_traverse_get_predicate (Lisp_Object thing, 
Lisp_Object language)
    return false, otherwise return true.  This function also check for
    recusion levels: we place a arbitrary 100 level limit on recursive
    predicates.  RECURSION_LEVEL is the current recursion level (that
-   starts at 0), if it goes over 99, return false and set
-   SIGNAL_DATA.  LANGUAGE is a LANGUAGE symbol.  */
+   starts at 0), if it goes over 99, return false and set SIGNAL_DATA.
+   LANGUAGE is a LANGUAGE symbol.  IGNORE_MISSING is as in
+   `treesit-node-match-p' below.  */
 static bool
 treesit_traverse_validate_predicate (Lisp_Object pred,
                                     Lisp_Object language,
                                     Lisp_Object *signal_data,
-                                    ptrdiff_t recursion_level)
+                                    ptrdiff_t recursion_level,
+                                    bool ignore_missing)
 {
   if (recursion_level > 99)
     {
@@ -3271,6 +3273,8 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
                                                               language);
       if (NILP (definition))
        {
+         if (ignore_missing)
+           return false;
          *signal_data = list2 (build_string ("Cannot find the definition "
                                              "of the predicate in "
                                              "`treesit-thing-settings'"),
@@ -3280,7 +3284,8 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
       return treesit_traverse_validate_predicate (definition,
                                                  language,
                                                  signal_data,
-                                                 recursion_level + 1);
+                                                 recursion_level + 1,
+                                                 ignore_missing);
     }
   else if (CONSP (pred))
     {
@@ -3306,7 +3311,8 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
          return treesit_traverse_validate_predicate (XCAR (cdr),
                                                      language,
                                                      signal_data,
-                                                     recursion_level + 1);
+                                                     recursion_level + 1,
+                                                     ignore_missing);
        }
       else if (BASE_EQ (car, Qor))
        {
@@ -3323,7 +3329,8 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
              if (!treesit_traverse_validate_predicate (XCAR (cdr),
                                                        language,
                                                        signal_data,
-                                                       recursion_level + 1))
+                                                       recursion_level + 1,
+                                                       ignore_missing))
                return false;
            }
          return true;
@@ -3512,8 +3519,10 @@ DEFUN ("treesit-search-subtree",
        doc: /* Traverse the parse tree of NODE depth-first using PREDICATE.
 
 Traverse the subtree of NODE, and match PREDICATE with each node along
-the way.  PREDICATE is a regexp string that matches against each
-node's type, or a function that takes a node and returns nil/non-nil.
+the way.  PREDICATE can be a regexp string that matches against each
+node's type, a predicate function, and more.  See
+`treesit-thing-settings' for the possible predicates.  PREDICATE can
+also be a thing defined in `treesit-thing-settings'.
 
 By default, only traverse named nodes, but if ALL is non-nil, traverse
 all nodes.  If BACKWARD is non-nil, traverse backwards.  If DEPTH is
@@ -3544,7 +3553,7 @@ Return the first matched node, or nil if none matches.  
*/)
 
   Lisp_Object signal_data = Qnil;
   if (!treesit_traverse_validate_predicate (predicate, language,
-                                           &signal_data, 0))
+                                           &signal_data, 0, false))
     xsignal1 (Qtreesit_invalid_predicate, signal_data);
 
   Lisp_Object return_value = Qnil;
@@ -3571,9 +3580,11 @@ DEFUN ("treesit-search-forward",
        doc: /* Search for node matching PREDICATE in the parse tree of START.
 
 Start traversing the tree from node START, and match PREDICATE with
-each node (except START itself) along the way.  PREDICATE is a regexp
-string that matches against each node's type, or a function that takes
-a node and returns non-nil if it matches.
+each node (except START itself) along the way.  PREDICATE can be a
+regexp string that matches against each node's type, a predicate
+function, and more.  See `treesit-thing-settings' for the possible
+predicates.  PREDICATE can also be a thing defined in
+`treesit-thing-settings'.
 
 By default, only search for named nodes, but if ALL is non-nil, search
 for all nodes.  If BACKWARD is non-nil, search backwards.
@@ -3609,7 +3620,7 @@ always traverse leaf nodes first, then upwards.  */)
 
   Lisp_Object signal_data = Qnil;
   if (!treesit_traverse_validate_predicate (predicate, language,
-                                           &signal_data, 0))
+                                           &signal_data, 0, false))
     xsignal1 (Qtreesit_invalid_predicate, signal_data);
 
   Lisp_Object return_value = Qnil;
@@ -3683,9 +3694,12 @@ DEFUN ("treesit-induce-sparse-tree",
        Streesit_induce_sparse_tree, 2, 4, 0,
        doc: /* Create a sparse tree of ROOT's subtree.
 
-This takes the subtree under ROOT, and combs it so only the nodes
-that match PREDICATE are left, like picking out grapes on the vine.
-PREDICATE is a regexp string that matches against each node's type.
+This takes the subtree under ROOT, and combs it so only the nodes that
+match PREDICATE are left, like picking out grapes on the vine.
+PREDICATE can be a regexp string that matches against each node's
+type, a predicate function, and more.  See `treesit-thing-settings'
+for the possible predicates.  PREDICATE can also be a thing defined in
+`treesit-thing-settings'.
 
 For a subtree on the left that consist of both numbers and letters, if
 PREDICATE is "is letter", the returned tree is the one on the right.
@@ -3741,7 +3755,7 @@ a regexp.  */)
 
   Lisp_Object signal_data = Qnil;
   if (!treesit_traverse_validate_predicate (predicate, language,
-                                           &signal_data, 0))
+                                           &signal_data, 0, false))
     xsignal1 (Qtreesit_invalid_predicate, signal_data);
 
   Lisp_Object parent = Fcons (Qnil, Qnil);
@@ -3767,13 +3781,20 @@ a regexp.  */)
 
 DEFUN ("treesit-node-match-p",
        Ftreesit_node_match_p,
-       Streesit_node_match_p, 2, 2, 0,
+       Streesit_node_match_p, 2, 3, 0,
        doc: /* Check whether NODE matches PREDICATE.
 
-PREDICATE can be a regexp matching node type, a predicate function,
-and more, see `treesit-thing-settings' for detail.  Return non-nil
-if NODE matches PRED, nil otherwise.  */)
-  (Lisp_Object node, Lisp_Object predicate)
+PREDICATE can be a symbol representing a thing in
+`treesit-thing-settings', or a predicate, like regexp matching node
+type, etc.  See `treesit-thing-settings' for more details.
+
+Return non-nil if NODE matches PREDICATE, nil otherwise.
+
+Signals `treesit-invalid-predicate' if there's no definition of THING
+in `treesit-thing-settings', or if PREDICATE is malformed.  If
+IGNORE-MISSING is non-nil, don't signal an error for missing THING
+definition, but still signal for malformed PREDICATE.  */)
+  (Lisp_Object node, Lisp_Object predicate, Lisp_Object ignore_missing)
 {
   CHECK_TS_NODE (node);
 
@@ -3782,7 +3803,8 @@ if NODE matches PRED, nil otherwise.  */)
 
   Lisp_Object signal_data = Qnil;
   if (!treesit_traverse_validate_predicate (predicate, language,
-                                           &signal_data, 0))
+                                           &signal_data, 0,
+                                           !NILP (ignore_missing)))
     xsignal1 (Qtreesit_invalid_predicate, signal_data);
 
   TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (node)->node);
@@ -3994,20 +4016,20 @@ LANGUAGE is a language symbol, and DEFINITIONS is a 
list of
     (THING PRED)
 
 THING is a symbol representing the thing, like `defun', `sexp', or
-`block'; PRED defines what kind of node can be qualified as THING.
+`sentence'; PRED defines what kind of node can be qualified as THING.
 
 PRED can be a regexp string that matches the type of the node; it can
 be a predicate function that takes the node as the sole argument and
-returns t if the node is the thing; it can be a cons (REGEXP . FN),
-which is a combination of a regexp and a predicate function, and the
-node has to match both to qualify as the thing.
+returns t if the node is the thing, and nil otherwise; it can be a
+cons (REGEXP . FN), which is a combination of a regexp and a predicate
+function, and the node has to match both to qualify as the thing.
 
 PRED can also be recursively defined.  It can be (or PRED...), meaning
 satisfying anyone of the inner PREDs qualifies the node; or (not
 PRED), meaning not satisfying the inner PRED qualifies the node.
 
 Finally, PRED can refer to other THINGs defined in this list by using
-the symbol of that THING.  For example, (or block sexp).  */);
+the symbol of that THING.  For example, (or sexp sentence).  */);
   Vtreesit_thing_settings = Qnil;
 
   staticpro (&Vtreesit_str_libtree_sitter);
diff --git a/test/lisp/cedet/semantic/bovine/gcc-tests.el 
b/test/lisp/cedet/semantic/bovine/gcc-tests.el
index 5437d65d139..0b703fcaa2f 100644
--- a/test/lisp/cedet/semantic/bovine/gcc-tests.el
+++ b/test/lisp/cedet/semantic/bovine/gcc-tests.el
@@ -31,62 +31,88 @@
 
 ;;; From bovine-gcc:
 
-;; Example output of "gcc -v"
-(defvar semantic-gcc-test-strings
-  '(;; My old box:
-    "Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs
+(defmacro semantic-gcc-test (str)
+  `(let ((fields (semantic-gcc-fields ,str)))
+     (let-alist fields
+       (message "%S" fields)
+       ;; No longer test for prefixes.
+       ;; (should .--prefix)
+       (should .version)
+       (should (or .target
+                   .--target
+                   .--host)))))
+
+;; A bunch of sample gcc -v outputs from different machines.
+
+(ert-deftest semantic-gcc-test/1 ()
+  ;; My old box:
+  (semantic-gcc-test "Reading specs from 
/usr/lib/gcc-lib/i386-redhat-linux/3.2.2/specs
 Configured with: ../configure --prefix=/usr --mandir=/usr/share/man 
--infodir=/usr/share/info --enable-shared --enable-threads=posix 
--disable-checking --with-system-zlib --enable-__cxa_atexit 
--host=i386-redhat-linux
 Thread model: posix
-gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"
-    ;; Alex Ott:
-    "Using built-in specs.
+gcc version 3.2.2 20030222 (Red Hat Linux 3.2.2-5)"))
+
+(ert-deftest semantic-gcc-test/2 ()
+  ;; Alex Ott:
+  (semantic-gcc-test "Using built-in specs.
 Target: i486-linux-gnu
 Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.3.1-9ubuntu1' 
--with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 
--program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-objc-gc --enable-mpfr --enable-targets=all --enable-chec [...]
 Thread model: posix
-gcc version 4.3.1 (Ubuntu 4.3.1-9ubuntu1)"
-    ;; My debian box:
-    "Using built-in specs.
+gcc version 4.3.1 (Ubuntu 4.3.1-9ubuntu1)"))
+
+(ert-deftest semantic-gcc-test/3 ()
+  ;; My Debian box:
+  (semantic-gcc-test "Using built-in specs.
 Target: x86_64-unknown-linux-gnu
 Configured with: ../../../sources/gcc/configure 
--prefix=/usr/local/glibc-2.3.6/x86_64/apps/gcc-4.2.3 
--with-gmp=/usr/local/gcc/gmp --with-mpfr=/usr/local/gcc/mpfr 
--enable-languages=c,c++,fortran 
--with-as=/usr/local/glibc-2.3.6/x86_64/apps/gcc-4.2.3/bin/as 
--with-ld=/usr/local/glibc-2.3.6/x86_64/apps/gcc-4.2.3/bin/ld --disable-multilib
 Thread model: posix
-gcc version 4.2.3"
-    ;; My mac:
-    "Using built-in specs.
+gcc version 4.2.3"))
+
+(ert-deftest semantic-gcc-test/4 ()
+  ;; My mac:
+  (semantic-gcc-test "Using built-in specs.
 Target: i686-apple-darwin8
 Configured with: /private/var/tmp/gcc/gcc-5341.obj~1/src/configure 
--disable-checking -enable-werror --prefix=/usr --mandir=/share/man 
--enable-languages=c,objc,c++,obj-c++ 
--program-transform-name=/^[cg][^.-]*$/s/$/-4.0/ 
--with-gxx-include-dir=/include/c++/4.0.0 --with-slibdir=/usr/lib 
--build=powerpc-apple-darwin8 --with-arch=pentium-m --with-tune=prescott 
--program-prefix= --host=i686-apple-darwin8 --target=i686-apple-darwin8
 Thread model: posix
-gcc version 4.0.1 (Apple Computer, Inc. build 5341)"
-    ;; Ubuntu Intrepid
-    "Using built-in specs.
+gcc version 4.0.1 (Apple Computer, Inc. build 5341)"))
+
+(ert-deftest semantic-gcc-test/5 ()
+  ;; Ubuntu Intrepid
+  (semantic-gcc-test "Using built-in specs.
 Target: x86_64-linux-gnu
 Configured with: ../src/configure -v --with-pkgversion='Ubuntu 
4.3.2-1ubuntu12' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 
--program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-objc-gc --enable-mpfr --enable-checking=release --build [...]
 Thread model: posix
-gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)"
-    ;; Red Hat EL4
-    "Reading specs from /usr/lib/gcc/x86_64-redhat-linux/3.4.6/specs
+gcc version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)"))
+
+(ert-deftest semantic-gcc-test/6 ()
+  ;; Red Hat EL4
+  (semantic-gcc-test "Reading specs from 
/usr/lib/gcc/x86_64-redhat-linux/3.4.6/specs
 Configured with: ../configure --prefix=/usr --mandir=/usr/share/man 
--infodir=/usr/share/info --enable-shared --enable-threads=posix 
--disable-checking --with-system-zlib --enable-__cxa_atexit 
--disable-libunwind-exceptions --enable-java-awt=gtk --host=x86_64-redhat-linux
 Thread model: posix
-gcc version 3.4.6 20060404 (Red Hat 3.4.6-10)"
-    ;; Red Hat EL5
-    "Using built-in specs.
+gcc version 3.4.6 20060404 (Red Hat 3.4.6-10)"))
+
+(ert-deftest semantic-gcc-test/7 ()
+  ;; Red Hat EL5
+  (semantic-gcc-test "Using built-in specs.
 Target: x86_64-redhat-linux
 Configured with: ../configure --prefix=/usr --mandir=/usr/share/man 
--infodir=/usr/share/info --enable-shared --enable-threads=posix 
--enable-checking=release --with-system-zlib --enable-__cxa_atexit 
--disable-libunwind-exceptions --enable-libgcj-multifile 
--enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk 
--disable-dssi --enable-plugin 
--with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic 
--host=x86_64-redhat-linux
 Thread model: posix
-gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)"
-    ;; David Engster's german gcc on ubuntu 4.3
-    "Es werden eingebaute Spezifikationen verwendet.
+gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)"))
+
+(ert-deftest semantic-gcc-test/8 ()
+  ;; David Engster's german gcc on ubuntu 4.3
+  (semantic-gcc-test "Es werden eingebaute Spezifikationen verwendet.
 Ziel: i486-linux-gnu
 Konfiguriert mit: ../src/configure -v --with-pkgversion='Ubuntu 
4.3.2-1ubuntu12' --with-bugurl=file:///usr/share/doc/gcc-4.3/README.Bugs 
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --enable-shared 
--with-system-zlib --libexecdir=/usr/lib --without-included-gettext 
--enable-threads=posix --enable-nls --with-gxx-include-dir=/usr/include/c++/4.3 
--program-suffix=-4.3 --enable-clocale=gnu --enable-libstdcxx-debug 
--enable-objc-gc --enable-mpfr --enable-targets=all --enable-ch [...]
 Thread-Modell: posix
-gcc-Version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)"
-    ;; Damien Deville bsd
-    "Using built-in specs.
+gcc-Version 4.3.2 (Ubuntu 4.3.2-1ubuntu12)"))
+
+(ert-deftest semantic-gcc-test/9 ()
+  ;; Damien Deville bsd
+  (semantic-gcc-test "Using built-in specs.
 Target: i386-undermydesk-freebsd
 Configured with: FreeBSD/i386 system compiler
 Thread model: posix
-gcc version 4.2.1 20070719  [FreeBSD]"
-    )
-  "A bunch of sample gcc -v outputs from different machines.")
+gcc version 4.2.1 20070719  [FreeBSD]"))
 
 (defvar semantic-gcc-test-strings-fail
   '(;; A really old solaris box I found
@@ -95,19 +121,8 @@ gcc version 2.95.2 19991024 (release)"
     )
   "A bunch of sample gcc -v outputs that fail to provide the info we want.")
 
-(defun semantic-gcc-test-output-parser ()
+(ert-deftest semantic-gcc-test-output-parser/fail ()
   "Test the output parser against some collected strings."
-  (dolist (S semantic-gcc-test-strings)
-    (let* ((fields (semantic-gcc-fields S))
-           (v (cdr (assoc 'version fields)))
-           (h (or (cdr (assoc 'target fields))
-                  (cdr (assoc '--target fields))
-                  (cdr (assoc '--host fields))))
-           (p (cdr (assoc '--prefix fields))))
-      ;; No longer test for prefixes.
-      (when (not (and v h))
-        (let ((strs (split-string S "\n")))
-          (error "Test failed on %S\nV H P:\n%S %S %S" (car strs) v h p)))))
   (dolist (S semantic-gcc-test-strings-fail)
     (let* ((fields (semantic-gcc-fields S))
            (v (cdr (assoc 'version fields)))
@@ -118,14 +133,10 @@ gcc version 2.95.2 19991024 (release)"
       (when (and v h p)
         (error "Negative test failed on %S" S)))))
 
-(ert-deftest semantic-gcc-test-output-parser ()
-  (semantic-gcc-test-output-parser))
-
-(ert-deftest semantic-gcc-test-output-parser-this-machine ()
+(ert-deftest semantic-gcc-test-output-parser/this-machine ()
   "Test the output parser against the machine currently running Emacs."
   (skip-unless (and (executable-find "gcc")
                     (not (ert-gcc-is-clang-p))))
-  (let ((semantic-gcc-test-strings (list (semantic-gcc-query "gcc" "-v"))))
-    (semantic-gcc-test-output-parser)))
+  (semantic-gcc-test (semantic-gcc-query "gcc" "-v")))
 
 ;;; gcc-tests.el ends here
diff --git a/test/lisp/epg-tests.el b/test/lisp/epg-tests.el
index 3659a922fe3..ed9da90c029 100644
--- a/test/lisp/epg-tests.el
+++ b/test/lisp/epg-tests.el
@@ -111,14 +111,23 @@ 
jA0ECQMCdW8+qtS9Tin/0jUBO1/9Oz69BWPmtFKEeBM62WpFP4o1+bNzdxogdyeg
 -----END PGP MESSAGE-----
 ")))))
 
+(defun epg--gnupg-version-is-not-buggy ()
+  ;; We need to skip some versions of GnuPG, as they make tests hang.
+  ;; See Bug#63256 and https://dev.gnupg.org/T6481 as well as PROBLEMS.
+  ;; Known bad versions for now are 2.4.1--2.4.3.
+  (not (string-match (rx bos "gpg (GnuPG) 2.4." (+ digit))
+                     (shell-command-to-string "gpg --version"))))
+
 (ert-deftest epg-roundtrip-1 ()
- :expected-result (if (getenv "EMACS_HYDRA_CI") :failed :passed) ; fixme
+  :expected-result (if (getenv "EMACS_HYDRA_CI") :failed :passed) ; fixme
+  (skip-unless (epg--gnupg-version-is-not-buggy))
   (with-epg-tests (:require-passphrase t)
     (let ((cipher (epg-encrypt-string epg-tests-context "symmetric" nil)))
       (should (equal "symmetric"
                     (epg-decrypt-string epg-tests-context cipher))))))
 
 (ert-deftest epg-roundtrip-2 ()
+  (skip-unless (epg--gnupg-version-is-not-buggy))
   (with-epg-tests (:require-passphrase t
                   :require-public-key t
                   :require-secret-key t)
diff --git a/test/lisp/eshell/em-prompt-tests.el 
b/test/lisp/eshell/em-prompt-tests.el
index 93bf9d84ab3..46e74e64983 100644
--- a/test/lisp/eshell/em-prompt-tests.el
+++ b/test/lisp/eshell/em-prompt-tests.el
@@ -32,6 +32,11 @@
                            (file-name-directory (or load-file-name
                                                     default-directory))))
 
+(defmacro em-prompt-test--with-multiline (&rest body)
+  "Execute BODY with a multiline Eshell prompt."
+  `(let ((eshell-prompt-function (lambda () "multiline prompt\n$ ")))
+     ,@body))
+
 ;;; Tests:
 
 (ert-deftest em-prompt-test/field-properties ()
@@ -80,64 +85,108 @@ This tests the case when `eshell-highlight-prompt' is nil."
                 (apply #'propertize "hello\n"
                        eshell-command-output-properties)))))))
 
-(defmacro em-prompt-test--with-multiline (&rest body)
-  "Execute BODY with a multiline Eshell prompt."
-  `(let ((eshell-prompt-function (lambda () "multiline prompt\n$ ")))
-     ,@body))
+(ert-deftest em-prompt-test/after-failure ()
+  "Check that current prompt shows the exit code of the last failed command."
+  (with-temp-eshell
+   (let ((debug-on-error nil))
+     (eshell-insert-command "(zerop \"foo\")"))
+   (let ((current-prompt (field-string (1- (point)))))
+     (should (equal-including-properties
+              current-prompt
+              (propertize
+               (concat (directory-file-name default-directory)
+                       (unless (eshell-exit-success-p)
+                         (format " [%d]" eshell-last-command-status))
+                       (if (= (file-user-uid) 0) " # " " $ "))
+               'read-only t
+               'field 'prompt
+               'font-lock-face 'eshell-prompt
+               'front-sticky '(read-only field font-lock-face)
+               'rear-nonsticky '(read-only field font-lock-face)))))))
 
-(defun em-prompt-test/next-previous-prompt-with ()
+(defun em-prompt-test/next-previous-prompt-1 ()
   "Helper for checking forward/backward navigation of old prompts."
   (with-temp-eshell
    (eshell-insert-command "echo one")
    (eshell-insert-command "echo two")
    (eshell-insert-command "echo three")
+   (let ((debug-on-error nil))          ; A failed command.
+     (eshell-insert-command "(zerop \"foo\")"))
    (insert "echo fou")                  ; A partially-entered command.
-   ;; Go back one prompt.
-   (eshell-previous-prompt 1)
-   (should (equal (eshell-get-old-input) "echo three"))
-   ;; Go back two prompts, starting from the end of this line.
-   (end-of-line)
-   (eshell-previous-prompt 2)
-   (should (equal (eshell-get-old-input) "echo one"))
-   ;; Go forward three prompts.
-   (eshell-next-prompt 3)
-   (should (equal (eshell-get-old-input) "echo fou"))))
+   (ert-info ("Go back one prompt")
+     (eshell-previous-prompt)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "(zerop \"foo\")\n")))
+   (ert-info ("Go back three prompts, starting from the end of the input")
+     (end-of-line)
+     (eshell-previous-prompt 3)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo one\n")))
+   (ert-info ("Go to the current prompt, starting from the end of the input")
+     (end-of-line)
+     (eshell-previous-prompt 0)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo one\n")))
+   (ert-info ("Go forward one prompt")
+     (eshell-next-prompt)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo two\n")))
+   (ert-info ("Go forward three prompts")
+     (eshell-next-prompt 3)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo fou")))
+   (ert-info ("Go back one prompt, starting from the beginning of the line")
+     (forward-line 0)
+     (eshell-previous-prompt 1)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "(zerop \"foo\")\n")))
+   (ert-info ("Go back one prompt, starting from the previous prompt's output")
+     (forward-line -1)
+     (eshell-previous-prompt 1)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo three\n")))))
 
 (ert-deftest em-prompt-test/next-previous-prompt ()
   "Check that navigating forward/backward through old prompts works correctly."
-  (em-prompt-test/next-previous-prompt-with))
+  (em-prompt-test/next-previous-prompt-1))
 
 (ert-deftest em-prompt-test/next-previous-prompt-multiline ()
   "Check old prompt forward/backward navigation for multiline prompts."
   (em-prompt-test--with-multiline
-   (em-prompt-test/next-previous-prompt-with)))
+   (em-prompt-test/next-previous-prompt-1)))
 
-(defun em-prompt-test/forward-backward-matching-input-with ()
+(defun em-prompt-test/forward-backward-matching-input-1 ()
   "Helper for checking forward/backward navigation via regexps."
   (with-temp-eshell
    (eshell-insert-command "echo one")
    (eshell-insert-command "printnl something else")
    (eshell-insert-command "echo two")
    (eshell-insert-command "echo three")
+   (let ((debug-on-error nil))          ; A failed command.
+     (eshell-insert-command "(zerop \"foo\")"))
    (insert "echo fou")                  ; A partially-entered command.
-   ;; Go back one prompt.
-   (eshell-backward-matching-input "echo" 1)
-   (should (equal (eshell-get-old-input) "echo three"))
-   ;; Go back two prompts, starting from the end of this line.
-   (end-of-line)
-   (eshell-backward-matching-input "echo" 2)
-   (should (equal (eshell-get-old-input) "echo one"))
-   ;; Go forward three prompts.
-   (eshell-forward-matching-input "echo" 3)
-   (should (equal (eshell-get-old-input) "echo fou"))))
+   (ert-info ("Search for \"echo\", back one prompt")
+     (eshell-backward-matching-input "echo" 1)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo three\n")))
+   (ert-info ((concat "Search for \"echo\", back two prompts, "
+                      "starting from the end of this line"))
+     (end-of-line)
+     (eshell-backward-matching-input "echo" 2)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo one\n")))
+   (ert-info ("Search for \"echo\", forward three prompts")
+     (eshell-forward-matching-input "echo" 3)
+     (should (equal (point) (field-beginning)))
+     (should (equal (field-string) "echo fou")))))
 
 (ert-deftest em-prompt-test/forward-backward-matching-input ()
   "Check that navigating forward/backward via regexps works correctly."
-  (em-prompt-test/forward-backward-matching-input-with))
+  (em-prompt-test/forward-backward-matching-input-1))
 
 (ert-deftest em-prompt-test/forward-backward-matching-input-multiline ()
   "Check forward/backward regexp navigation for multiline prompts."
   (em-prompt-test--with-multiline
-   (em-prompt-test/forward-backward-matching-input-with)))
+   (em-prompt-test/forward-backward-matching-input-1)))
 
 ;;; em-prompt-tests.el ends here
diff --git a/test/lisp/eshell/esh-util-tests.el 
b/test/lisp/eshell/esh-util-tests.el
index fe4eb9f31dd..7bd71b260ff 100644
--- a/test/lisp/eshell/esh-util-tests.el
+++ b/test/lisp/eshell/esh-util-tests.el
@@ -19,9 +19,15 @@
 
 ;;; Code:
 
+(require 'tramp)
 (require 'ert)
 (require 'esh-util)
 
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
 ;;; Tests:
 
 (ert-deftest esh-util-test/eshell-stringify/string ()
@@ -156,4 +162,28 @@
 (ert-deftest esh-util-test/eshell-printable-size/human-readable-arg ()
   (should-error (eshell-printable-size 0 999 nil t)))
 
+(ert-deftest esh-util-test/path/get ()
+  "Test that getting the Eshell path returns the expected results."
+  (let ((expected-path (butlast (exec-path))))
+    (should (equal (eshell-get-path)
+                   (if (eshell-under-windows-p)
+                       (cons "." expected-path)
+                     expected-path)))
+    (should (equal (eshell-get-path 'literal)
+                   expected-path))))
+
+(ert-deftest esh-util-test/path/get-remote ()
+  "Test that getting the remote Eshell path returns the expected results."
+  (let* ((default-directory ert-remote-temporary-file-directory)
+         (expected-path (butlast (exec-path))))
+    ;; Make sure we don't have a doubled directory separator.
+    (should (seq-every-p (lambda (i) (not (string-match-p "//" i)))
+                         (eshell-get-path)))
+    (should (equal (eshell-get-path)
+                   (mapcar (lambda (i)
+                             (concat (file-remote-p default-directory) i))
+                           expected-path)))
+    (should (equal (eshell-get-path 'literal)
+                   expected-path))))
+
 ;;; esh-util-tests.el ends here
diff --git a/test/lisp/eshell/eshell-tests-helpers.el 
b/test/lisp/eshell/eshell-tests-helpers.el
index 2c913d71cb4..c983c8fd2bb 100644
--- a/test/lisp/eshell/eshell-tests-helpers.el
+++ b/test/lisp/eshell/eshell-tests-helpers.el
@@ -54,6 +54,13 @@ beginning of the test file."
        (let* (;; We want no history file, so prevent Eshell from falling
               ;; back on $HISTFILE.
               (process-environment (cons "HISTFILE" process-environment))
+              ;; Enable process debug instrumentation.  We may be able
+              ;; to remove this eventually once we're confident that
+              ;; all the process bugs have been worked out.  (At that
+              ;; point, we can just enable this selectively when
+              ;; needed.)  See also `eshell-test-command-result'
+              ;; below.
+              (eshell-debug-command (cons 'process eshell-debug-command))
               (eshell-history-file-name nil)
               (eshell-last-dir-ring-file-name nil)
               (eshell-buffer (eshell t)))
@@ -96,6 +103,13 @@ raise an error."
    (lambda ()
      (not (if all eshell-process-list (eshell-interactive-process-p))))))
 
+(defun eshell-get-debug-logs ()
+  "Get debug command logs for displaying on test failures."
+  (when (get-buffer eshell-debug-command-buffer)
+    (let ((separator (make-string 40 ?-)))
+      (with-current-buffer eshell-debug-command-buffer
+        (string-replace "\f" separator (buffer-string))))))
+
 (defun eshell-insert-command (command &optional func)
   "Insert a COMMAND at the end of the buffer.
 After inserting, call FUNC.  If FUNC is nil, instead call
@@ -135,17 +149,21 @@ FUNC is the function to call after inserting the text (see
 
 If IGNORE-ERRORS is non-nil, ignore any errors signaled when
 inserting the command."
-  (let ((debug-on-error (and (not ignore-errors) debug-on-error)))
-    (eshell-insert-command command func))
-  (eshell-wait-for-subprocess)
-  (should (eshell-match-output regexp)))
+  (ert-info (#'eshell-get-debug-logs :prefix "Command logs: ")
+    (let ((debug-on-error (and (not ignore-errors) debug-on-error)))
+      (eshell-insert-command command func))
+    (eshell-wait-for-subprocess)
+    (should (eshell-match-output regexp))))
 
 (defvar eshell-history-file-name)
 
 (defun eshell-test-command-result (command)
   "Like `eshell-command-result', but not using HOME."
   (ert-with-temp-directory eshell-directory-name
-    (let ((eshell-history-file-name nil))
+    (let ((eshell-history-file-name nil)
+          ;; Enable process debug instrumentation.  See
+          ;; `with-temp-eshell' above.
+          (eshell-debug-command (cons 'process eshell-debug-command)))
       (eshell-command-result command))))
 
 (defun eshell-command-result--equal (_command actual expected)
@@ -164,10 +182,11 @@ inserting the command."
 
 (defun eshell-command-result-equal (command result)
   "Execute COMMAND non-interactively and compare it to RESULT."
-  (should (eshell-command-result--equal
-           command
-           (eshell-test-command-result command)
-           result)))
+  (ert-info (#'eshell-get-debug-logs :prefix "Command logs: ")
+    (should (eshell-command-result--equal
+             command
+             (eshell-test-command-result command)
+             result))))
 
 (provide 'eshell-tests-helpers)
 
diff --git a/test/lisp/proced-tests.el b/test/lisp/proced-tests.el
index bffbf5486d3..44596f92490 100644
--- a/test/lisp/proced-tests.el
+++ b/test/lisp/proced-tests.el
@@ -1,6 +1,6 @@
 ;;; proced-tests.el --- Test suite for proced.el -*- lexical-binding: t -*-
 
-;; Copyright (C) 2022 Free Software Foundation, Inc.
+;; Copyright (C) 2022-2023 Free Software Foundation, Inc.
 
 ;; This file is part of GNU Emacs.
 
@@ -18,6 +18,7 @@
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Code:
+
 (require 'ert)
 (require 'proced)
 (require 'thingatpt)
diff --git a/test/lisp/vc/vc-tests.el b/test/lisp/vc/vc-tests.el
index 11c20d2783c..0a26e25e32a 100644
--- a/test/lisp/vc/vc-tests.el
+++ b/test/lisp/vc/vc-tests.el
@@ -596,8 +596,9 @@ This checks also `vc-backend' and `vc-responsible-backend'."
     (let ((vc-handled-backends `(,backend))
           (default-directory
            (file-name-as-directory
-            (expand-file-name
-             (make-temp-name "vc-test") temporary-file-directory)))
+            (file-truename
+             (expand-file-name
+              (make-temp-name "vc-test") temporary-file-directory))))
           (process-environment process-environment)
           vc-test--cleanup-hook)
       (when (eq backend 'Bzr)



reply via email to

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