emacs-diffs
[Top][All Lists]
Advanced

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

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


From: Gerd Moellmann
Subject: scratch/pkg f0edf8dd04c: Merge remote-tracking branch 'origin/master' into scratch/pkg
Date: Tue, 19 Dec 2023 00:51:26 -0500 (EST)

branch: scratch/pkg
commit f0edf8dd04cfcad101faf90434cffa95c416d776
Merge: a0e61826a2c 20e39a12e49
Author: Gerd Möllmann <gerd@gnu.org>
Commit: Gerd Möllmann <gerd@gnu.org>

    Merge remote-tracking branch 'origin/master' into scratch/pkg
---
 ChangeLog.2                                        |   12 +-
 ChangeLog.3                                        |   90 +-
 ChangeLog.4                                        |  672 ++++----
 ChangeLog.android                                  |   26 +-
 admin/notes/java                                   |    6 +-
 configure.ac                                       |    7 +-
 cross/ndk-build/README                             |    4 +-
 doc/emacs/ChangeLog.1                              |    4 +-
 doc/emacs/android.texi                             |   24 +-
 doc/emacs/cmdargs.texi                             |    5 +
 doc/emacs/dired.texi                               |    4 +
 doc/emacs/files.texi                               |    4 +
 doc/emacs/haiku.texi                               |    2 +-
 doc/lispintro/emacs-lisp-intro.texi                |    2 +-
 doc/lispref/commands.texi                          |    4 +-
 doc/lispref/display.texi                           |   14 +-
 doc/lispref/files.texi                             |    7 +-
 doc/lispref/frames.texi                            |    6 +-
 doc/lispref/functions.texi                         |   34 +
 doc/lispref/keymaps.texi                           |    2 +-
 doc/lispref/minibuf.texi                           |    2 +-
 doc/lispref/parsing.texi                           |    4 +-
 doc/lispref/processes.texi                         |   28 +-
 doc/lispref/searching.texi                         |    2 +-
 doc/lispref/text.texi                              |  107 +-
 doc/lispref/variables.texi                         |   31 +-
 doc/lispref/windows.texi                           |   19 +-
 doc/misc/ChangeLog.1                               |    2 +-
 doc/misc/calc.texi                                 |    2 +-
 doc/misc/eglot.texi                                |   48 +-
 doc/misc/epa.texi                                  |    4 +-
 doc/misc/erc.texi                                  |   46 +-
 doc/misc/ert.texi                                  |   97 ++
 doc/misc/eshell.texi                               |   19 +-
 doc/misc/gnus.texi                                 |   33 +-
 doc/misc/modus-themes.org                          |   22 +-
 doc/misc/tramp.texi                                |   38 +-
 doc/misc/transient.texi                            |  969 +++++-------
 doc/misc/url.texi                                  |    2 -
 doc/misc/widget.texi                               |    6 +-
 etc/DEBUG                                          |    2 +-
 etc/ERC-NEWS                                       |  155 +-
 etc/NEWS                                           |  118 +-
 etc/ORG-NEWS                                       |    2 +-
 etc/PROBLEMS                                       |    4 +-
 etc/images/symbols/minus_16.pbm                    |  Bin 41 -> 41 bytes
 etc/images/symbols/minus_16.svg                    |    2 +-
 etc/images/symbols/plus_16.pbm                     |  Bin 41 -> 41 bytes
 etc/images/symbols/plus_16.svg                     |    2 +-
 etc/publicsuffix.txt                               |  573 ++++++-
 etc/refcards/orgcard.tex                           |    2 +-
 etc/themes/modus-operandi-tinted-theme.el          |    4 +-
 etc/themes/modus-themes.el                         |    2 +-
 exec/exec1.c                                       |    2 +-
 exec/loader-armeabi.s                              |    2 +-
 exec/loader-mips64el.s                             |    2 +-
 exec/loader-mipsel.s                               |    2 +-
 exec/trace.c                                       |    2 +-
 java/AndroidManifest.xml.in                        |    4 +-
 java/INSTALL                                       |    4 +-
 java/org/gnu/emacs/EmacsContextMenu.java           |    2 +-
 java/org/gnu/emacs/EmacsInputConnection.java       |    2 +-
 java/org/gnu/emacs/EmacsOpenActivity.java          |    2 +-
 java/org/gnu/emacs/EmacsSafThread.java             |   12 +-
 java/org/gnu/emacs/EmacsService.java               |    8 +-
 java/org/gnu/emacs/EmacsView.java                  |    2 +-
 java/org/gnu/emacs/EmacsWindow.java                |   32 +-
 lisp/ChangeLog.12                                  |    2 +-
 lisp/ChangeLog.13                                  |    2 +-
 lisp/ChangeLog.14                                  |    6 +-
 lisp/ChangeLog.15                                  |    2 +-
 lisp/ChangeLog.16                                  |    4 +-
 lisp/ChangeLog.17                                  |    2 +-
 lisp/ChangeLog.7                                   |    2 +-
 lisp/button.el                                     |    2 +-
 lisp/calc/calc.el                                  |    2 +
 lisp/cedet/ChangeLog.1                             |    2 +-
 lisp/cedet/semantic/complete.el                    |    2 +-
 lisp/cedet/srecode/extract.el                      |    2 +-
 lisp/cedet/srecode/srt-mode.el                     |    2 +-
 lisp/completion-preview.el                         |   16 +-
 lisp/desktop.el                                    |    2 +-
 lisp/dired-aux.el                                  |   39 +-
 lisp/dired-x.el                                    |    3 +-
 lisp/dired.el                                      |   27 +-
 lisp/emacs-lisp/byte-opt.el                        |    6 +-
 lisp/emacs-lisp/bytecomp.el                        |   10 +-
 lisp/emacs-lisp/cl-macs.el                         |    2 +-
 lisp/emacs-lisp/comp-common.el                     |    9 +-
 lisp/emacs-lisp/comp-cstr.el                       |    2 +-
 lisp/emacs-lisp/comp-run.el                        |    1 +
 lisp/emacs-lisp/comp.el                            |  198 +--
 lisp/emacs-lisp/debug.el                           |   62 +-
 lisp/emacs-lisp/eldoc.el                           |   34 +-
 lisp/emacs-lisp/ert-font-lock.el                   |  364 +++++
 lisp/emacs-lisp/ert.el                             |    2 +-
 lisp/emacs-lisp/gv.el                              |    2 +-
 lisp/emacs-lisp/lisp.el                            |    2 +-
 lisp/emacs-lisp/macroexp.el                        |   23 +-
 lisp/emacs-lisp/nadvice.el                         |    2 -
 lisp/emacs-lisp/package-vc.el                      |   13 +-
 lisp/emacs-lisp/package.el                         |   30 +-
 lisp/erc/erc-backend.el                            |  188 ++-
 lisp/erc/erc-button.el                             |   80 +-
 lisp/erc/erc-common.el                             |  109 +-
 lisp/erc/erc-dcc.el                                |   15 +-
 lisp/erc/erc-fill.el                               |  149 +-
 lisp/erc/erc-goodies.el                            |    2 +-
 lisp/erc/erc-netsplit.el                           |   13 +-
 lisp/erc/erc-networks.el                           |   23 +-
 lisp/erc/erc-nicks.el                              |   92 +-
 lisp/erc/erc-notify.el                             |   81 +-
 lisp/erc/erc-page.el                               |    3 +-
 lisp/erc/erc-sasl.el                               |    5 +-
 lisp/erc/erc-services.el                           |    2 +-
 lisp/erc/erc-sound.el                              |    3 +-
 lisp/erc/erc-speedbar.el                           |    4 +-
 lisp/erc/erc-stamp.el                              |   27 +-
 lisp/erc/erc-status-sidebar.el                     |    2 +-
 lisp/erc/erc-track.el                              |  270 +++-
 lisp/erc/erc.el                                    |  821 +++++++---
 lisp/eshell/em-hist.el                             |   18 +-
 lisp/eshell/em-unix.el                             |    2 +-
 lisp/files-x.el                                    |   36 +-
 lisp/files.el                                      |   14 +-
 lisp/filesets.el                                   |   12 +-
 lisp/gnus/ChangeLog.1                              |    4 +-
 lisp/gnus/ChangeLog.2                              |    4 +-
 lisp/gnus/ChangeLog.3                              |    4 +-
 lisp/gnus/gnus-art.el                              |   15 +-
 lisp/gnus/gnus-group.el                            |   56 +-
 lisp/gnus/gnus-msg.el                              |   26 +-
 lisp/gnus/gnus-search.el                           |    2 +-
 lisp/gnus/message.el                               |   10 +-
 lisp/gnus/nndiary.el                               |    2 +-
 lisp/gnus/nnml.el                                  |    2 +-
 lisp/indent.el                                     |    2 +-
 lisp/jsonrpc.el                                    |  330 ++--
 lisp/language/hanja-util.el                        |    2 +-
 lisp/language/sinhala.el                           |    6 +-
 lisp/ldefs-boot.el                                 |  847 +++++++---
 lisp/loadup.el                                     |   28 +-
 lisp/mail/emacsbug.el                              |    4 +-
 lisp/mail/rmailout.el                              |    2 +-
 lisp/man.el                                        |    2 +-
 lisp/mh-e/ChangeLog.1                              |    2 +-
 lisp/mh-e/ChangeLog.2                              |    2 +-
 lisp/minibuffer.el                                 |  120 +-
 lisp/net/ange-ftp.el                               |    3 +-
 lisp/net/newst-treeview.el                         |    2 +-
 lisp/net/shr.el                                    |   10 +-
 lisp/net/sieve-manage.el                           |    4 +-
 lisp/net/soap-client.el                            |    2 +-
 lisp/net/tramp-cache.el                            |    8 +-
 lisp/net/tramp-compat.el                           |   11 +
 lisp/net/tramp-crypt.el                            |   25 +-
 lisp/net/tramp-message.el                          |    2 +-
 lisp/net/tramp-sh.el                               |   14 +-
 lisp/net/tramp.el                                  |    6 +-
 lisp/org/ChangeLog.1                               |   16 +-
 lisp/org/ob-plantuml.el                            |    2 +-
 lisp/org/oc-biblatex.el                            |    2 +-
 lisp/org/oc.el                                     |    2 +-
 lisp/org/org-capture.el                            |    2 +-
 lisp/org/org-compat.el                             |    2 +-
 lisp/org/org-element.el                            |   10 +-
 lisp/org/org-macs.el                               |   13 +-
 lisp/org/org-persist.el                            |   19 +-
 lisp/org/org-table.el                              |    2 +-
 lisp/org/org-version.el                            |    4 +-
 lisp/org/org.el                                    |   12 +-
 lisp/org/ox-beamer.el                              |    2 +-
 lisp/progmodes/asm-mode.el                         |    8 +-
 lisp/progmodes/c-ts-common.el                      |    4 +-
 lisp/progmodes/c-ts-mode.el                        |   71 +-
 lisp/progmodes/cc-engine.el                        |    6 +-
 lisp/progmodes/cc-mode.el                          |    3 +
 lisp/progmodes/compile.el                          |    2 +-
 lisp/progmodes/cperl-mode.el                       |    6 +-
 lisp/progmodes/eglot.el                            |  109 +-
 lisp/progmodes/gud.el                              |    6 +-
 lisp/progmodes/hideif.el                           |    2 +-
 lisp/progmodes/js.el                               |   57 +-
 lisp/progmodes/lua-ts-mode.el                      |    8 +-
 lisp/progmodes/perl-mode.el                        |    4 +-
 lisp/progmodes/project.el                          |   22 +-
 lisp/progmodes/python.el                           |    3 +-
 lisp/progmodes/ruby-mode.el                        |   24 +-
 lisp/progmodes/ruby-ts-mode.el                     |    2 +-
 lisp/progmodes/rust-ts-mode.el                     |   10 +-
 lisp/progmodes/typescript-ts-mode.el               |    2 +-
 lisp/register.el                                   |   51 +-
 lisp/ses.el                                        |    2 +-
 lisp/simple.el                                     |   17 +-
 lisp/startup.el                                    |   19 +-
 lisp/subr.el                                       |   13 +-
 lisp/tab-bar.el                                    |    2 +
 lisp/tab-line.el                                   |    2 +
 lisp/term.el                                       |   13 +-
 lisp/term/android-win.el                           |   57 +-
 lisp/term/linux.el                                 |    6 +-
 lisp/textmodes/ispell.el                           |    1 -
 lisp/thingatpt.el                                  |    2 +-
 lisp/touch-screen.el                               |    8 +-
 lisp/transient.el                                  | 1616 +++++++++++---------
 lisp/treesit.el                                    |    7 +-
 lisp/url/url-http.el                               |    4 -
 lisp/url/url-privacy.el                            |   10 -
 lisp/url/url-vars.el                               |    9 +-
 lisp/use-package/use-package-core.el               |    4 +-
 lisp/vc/log-edit.el                                |    4 +-
 lisp/vc/log-view.el                                |    6 +-
 lisp/vc/vc-git.el                                  |   49 +-
 lisp/vc/vc-hg.el                                   |   17 +
 lisp/vc/vc-rcs.el                                  |    2 +-
 lisp/vc/vc.el                                      |   78 +-
 lisp/window.el                                     |   33 +-
 lisp/xt-mouse.el                                   |   10 +-
 src/ChangeLog.11                                   |    6 +-
 src/ChangeLog.13                                   |    6 +-
 src/ChangeLog.8                                    |    2 +-
 src/ChangeLog.9                                    |    2 +-
 src/android.c                                      |   16 +-
 src/androidfns.c                                   |  207 +++
 src/androidselect.c                                |    2 +-
 src/androidterm.c                                  |    4 +-
 src/androidterm.h                                  |    2 +-
 src/androidvfs.c                                   |    8 +-
 src/conf_post.h                                    |    2 +-
 src/eval.c                                         |   20 +-
 src/fileio.c                                       |    2 +-
 src/image.c                                        |    4 +-
 src/itree.c                                        |    2 +-
 src/pgtkterm.c                                     |    2 +-
 src/print.c                                        |    2 +-
 src/process.c                                      |    2 +-
 src/regex-emacs.c                                  |    2 +-
 src/sfnt.c                                         | 1129 +++++++++++++-
 src/sfnt.h                                         |    6 +-
 src/sfntfont.c                                     |   19 +-
 src/textconv.c                                     |    6 +-
 src/tparam.c                                       |    2 +-
 src/treesit.c                                      |   11 +-
 src/window.c                                       |    2 +-
 src/window.h                                       |    2 +-
 src/xdisp.c                                        |   36 +-
 src/xfont.c                                        |    2 +-
 src/xselect.c                                      |    2 +-
 src/xterm.c                                        |   12 +-
 test/lisp/emacs-lisp/bytecomp-tests.el             |    8 +-
 .../emacs-lisp/ert-font-lock-resources/broken.js   |    3 +
 .../emacs-lisp/ert-font-lock-resources/correct.js  |    3 +
 test/lisp/emacs-lisp/ert-font-lock-tests.el        |  464 ++++++
 test/lisp/erc/erc-fill-tests.el                    |   11 +-
 test/lisp/erc/erc-nicks-tests.el                   |    2 +-
 test/lisp/erc/erc-scenarios-base-attach.el         |    4 +-
 test/lisp/erc/erc-scenarios-base-reconnect.el      |    2 +-
 test/lisp/erc/erc-scenarios-base-renick.el         |    2 +-
 test/lisp/erc/erc-scenarios-base-statusmsg.el      |  103 ++
 test/lisp/erc/erc-scenarios-display-message.el     |    4 +-
 test/lisp/erc/erc-scenarios-match.el               |   14 +-
 test/lisp/erc/erc-scenarios-misc-commands.el       |   32 +
 test/lisp/erc/erc-scenarios-stamp.el               |   20 +-
 test/lisp/erc/erc-stamp-tests.el                   |    2 +-
 test/lisp/erc/erc-tests.el                         |  482 +++++-
 test/lisp/erc/erc-track-tests.el                   |  166 ++
 .../resources/base/display-message/statusmsg.eld   |   47 +
 test/lisp/erc/resources/commands/vhost.eld         |   40 +
 .../resources/fill/snapshots/merge-01-start.eld    |    2 +-
 .../resources/fill/snapshots/merge-02-right.eld    |    2 +-
 .../erc/resources/fill/snapshots/merge-wrap-01.eld |    2 +-
 .../snapshots/merge-wrap-indicator-post-01.eld     |    2 +-
 .../fill/snapshots/merge-wrap-indicator-pre-01.eld |    2 +-
 .../fill/snapshots/monospace-01-start.eld          |    2 +-
 .../fill/snapshots/monospace-02-right.eld          |    2 +-
 .../resources/fill/snapshots/monospace-03-left.eld |    2 +-
 .../fill/snapshots/monospace-04-reset.eld          |    2 +-
 .../resources/fill/snapshots/spacing-01-mono.eld   |    2 +-
 .../resources/fill/snapshots/stamps-left-01.eld    |    2 +-
 .../erc/resources/join/network-id/foonet-again.eld |    2 +-
 test/lisp/eshell/em-hist-tests.el                  |    2 +-
 test/lisp/eshell/esh-io-tests.el                   |    2 +-
 test/lisp/files-x-tests.el                         |   76 +
 test/lisp/international/mule-tests.el              |    2 +-
 test/lisp/jsonrpc-tests.el                         |    9 +-
 test/lisp/net/tramp-tests.el                       |    4 +-
 test/lisp/proced-tests.el                          |    2 +-
 .../progmodes/c-ts-mode-resources/indent-bsd.erts  |   34 +
 .../lisp/progmodes/c-ts-mode-resources/indent.erts |   48 +-
 test/lisp/progmodes/eglot-tests.el                 |   40 +-
 .../lisp/progmodes/js-resources/js-ts-indents.erts |   44 +
 test/lisp/progmodes/js-tests.el                    |    6 +
 .../progmodes/lua-ts-mode-resources/font-lock.lua  |  339 ++++
 test/lisp/progmodes/lua-ts-mode-tests.el           |   10 +-
 test/lisp/progmodes/perl-mode-tests.el             |    2 +-
 test/lisp/progmodes/ruby-mode-resources/ruby.rb    |    6 +-
 test/lisp/progmodes/ruby-mode-tests.el             |   12 +
 test/lisp/thingatpt-tests.el                       |    6 +-
 test/src/comp-resources/comp-test-funcs.el         |   16 +
 test/src/comp-tests.el                             |    4 +
 test/src/regex-emacs-tests.el                      |    2 +-
 301 files changed, 10102 insertions(+), 3763 deletions(-)

diff --git a/ChangeLog.2 b/ChangeLog.2
index d40401093c5..ee816281427 100644
--- a/ChangeLog.2
+++ b/ChangeLog.2
@@ -8956,10 +8956,10 @@
 
 2016-02-04  Carlos Pita  <carlosjosepita@gmail.com>  (tiny change)
 
-       Make complection in erc use consistent casing
+       Make completion in erc use consistent casing
 
        * lisp/erc/erc-pcomplete.el (pcomplete-erc-all-nicks): Make
-       case in the complection consistent (bug#18509).
+       case in the completion consistent (bug#18509).
 
 2016-02-04  Francis Litterio  <flitterio@gmail.com>
 
@@ -17094,11 +17094,11 @@
        * lisp/json.el (json-encoding-object-sort-predicate): New variable
        for specifying a sorting predicate for JSON objects during encoding.
        (json--plist-to-alist): New utility function.
-       (json-encode-hash-table): Re-use `json-encode-alist' when object keys
+       (json-encode-hash-table): Reuse `json-encode-alist' when object keys
        are to be sorted.
        (json-encode-alist): Sort output by
        `json-encoding-object-sort-predicate, when set.
-       (json-encode-plist): Re-use `json-encode-alist' when object keys are
+       (json-encode-plist): Reuse `json-encode-alist' when object keys are
        to be sorted.
        (json-pretty-print-buffer-ordered): New command to pretty print the
        buffer with object keys sorted alphabetically.
@@ -19542,7 +19542,7 @@
        calling low-level functions.
 
        * test/automated/file-notify-tests.el (file-notify--test-timeout):
-       Decrase to 6 seconds for remote directories.
+       Decrease to 6 seconds for remote directories.
        (file-notify-test02-events): Expect different number of
        `attribute-changed' events for the local and remote cases.  Apply
        short delays between the operations, in order to receive all
@@ -32624,7 +32624,7 @@
        (verilog-set-auto-endcomments): Fix end comments for functions of
        type void, etc.  Reported by Alex Reed.
        (verilog-do-indent): Fix electric tab deleting form-feeds.  Note
-       caused by indent-line-to deleting tabls pre 24.5.
+       caused by indent-line-to deleting tables pre 24.5.
        (verilog-nameable-item-re): Fix nameable items that can have an
        end-identifier to include endchecker, endgroup, endprogram,
        endproperty, and endsequence.  Reported by Alex Reed.
diff --git a/ChangeLog.3 b/ChangeLog.3
index d831b14178c..f0181337d10 100644
--- a/ChangeLog.3
+++ b/ChangeLog.3
@@ -146,7 +146,7 @@
 
 2022-10-04  Andreas Schwab  <schwab@linux-m68k.org>
 
-       * src/emacs.c (load_pdump): Propery handle case when executable
+       * src/emacs.c (load_pdump): Properly handle case when executable
        wasn't found.
 
 2022-10-04  Eli Zaretskii  <eliz@gnu.org>
@@ -6570,7 +6570,7 @@
 
 2021-10-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Mention ffap-file-name-with-spaces in the ffap doc strin
+       Mention ffap-file-name-with-spaces in the ffap doc string
 
        * lisp/ffap.el (find-file-at-point): Mention
        ffap-file-name-with-spaces in the doc string.
@@ -7174,7 +7174,7 @@
 
        (ess-eval-visibly-p): Declare.
        (org-babel-julia-assign-elisp): Remove unused vars `header` and
-       `row-names` and corespondingly remove now unused args `colnames-p` and
+       `row-names` and correspondingly remove now unused args `colnames-p` and
        `rownames-p`.
        (org-babel-variable-assignments:julia): Adjust call to
        `org-babel-julia-assign-elisp` accordingly.
@@ -10203,7 +10203,7 @@
 
 2021-09-17  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Mention that the garbage collection is convervative
+       Mention that the garbage collection is conservative
 
        * doc/lispref/internals.texi (Garbage Collection): Mention that
        we're using a conservative gc (bug#42013).
@@ -21832,7 +21832,7 @@
        * src/doprnt.c (exprintf, evxprintf):
        * src/lisp.h (exprintf, evxprintf): Don't use a pointer-to-const type
        for the `nonheapbuf` argument: although it is never dereferenced, GCC
-       will warn when passing a pointer to uninitialised memory otherwise.
+       will warn when passing a pointer to uninitialized memory otherwise.
        * src/fns.c (sort_vector_copy, realize_face, realize_gui_face)
        (realize_tty_face): Use the same signatures in the prototypes as in
        the actual function definitions.
@@ -23755,7 +23755,7 @@
 
 2021-05-29  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Improve the file-accessible-directory-p doc strin
+       Improve the file-accessible-directory-p doc string
 
        * src/fileio.c (Ffile_accessible_directory_p): Don't use the
        phrase "directory name spec", which isn't defined (bug#18201).
@@ -44752,7 +44752,7 @@
        (nxml-prefer-utf-16-little-to-big-endian-flag)
        (nxml-default-buffer-file-coding-system)
        (nxml-auto-insert-xml-declaration-flag): Add :safe to allow easier
-       cusomization (bug#45969).
+       customization (bug#45969).
 
 2021-01-19  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -47582,10 +47582,10 @@
 
 2020-12-30  Andrea Corallo  <akrl@sdf.org>
 
-       Order function types in aphabetical order
+       Order function types in alphabetical order
 
        * lisp/emacs-lisp/comp.el (comp-known-type-specifiers): Reorder in
-       aphabetical order and comment.
+       alphabetical order and comment.
 
 2020-12-30  Andrea Corallo  <akrl@sdf.org>
 
@@ -55395,7 +55395,7 @@
 
 2020-11-18  Andrea Corallo  <akrl@sdf.org>
 
-       Fix eln file hasing for symlink paths (bug#44701)
+       Fix eln file hashing for symlink paths (bug#44701)
 
        * src/comp.c (Fcomp_el_to_eln_filename): Call `file-truename'
        in place of `expand-file-name' when available.
@@ -55928,7 +55928,7 @@
        Fix debug symbol emission
 
        * src/comp.c (Fcomp__compile_ctxt_to_file): Now that we do not
-       rely anymore on globlal variables move logic in from
+       rely anymore on global variables move logic in from
        'Fcomp__init_ctxt' so comp.debug is already set correctly.
 
 2020-11-14  Andrea Corallo  <akrl@sdf.org>
@@ -59251,7 +59251,7 @@
 
 2020-10-26  Andrea Corallo  <akrl@sdf.org>
 
-       Make native compiler tollerant to redefined primitives (bug#44221).
+       Make native compiler tolerant to redefined primitives (bug#44221).
 
        * lisp/emacs-lisp/comp.el (comp-emit-set-call-subr): Rework based
        on the fact that the subr can now be redefined.
@@ -59833,7 +59833,7 @@
        Fix error in tramp-sh-handle-make-process
 
        * lisp/net/tramp-sh.el (tramp-sh-handle-make-process): Don't use heredoc
-       script whent the argument contains a string.
+       script when the argument contains a string.
 
 2020-10-23  Stefan Kangas  <stefan@marxist.se>
 
@@ -64846,7 +64846,7 @@
 
 2020-09-24  Andrea Corallo  <akrl@sdf.org>
 
-       Add a test for primitive advicing effectiveness
+       Add a test for primitive advising effectiveness
 
        * test/src/comp-test-funcs.el (comp-test-primitive-advice-f): New
        function.
@@ -64903,7 +64903,7 @@
        install a subr trampoline into the function relocation table.
        Once this is done any call from native compiled Lisp to the
        related primitive will go through the `funcall' trampoline
-       making advicing effective.
+       making advising effective.
 
 2020-09-23  Andrea Corallo  <akrl@sdf.org>
 
@@ -70385,7 +70385,7 @@
        (MD5_BLOCKSIZE): New macro.
        (accumulate_and_process_md5, final_process_md5, md5_gz_stream)
        (comp_hash_source_file): New functions.
-       (Fcomp_el_to_eln_filename): Rework for hasing using also source
+       (Fcomp_el_to_eln_filename): Rework for hashing using also source
        file content.
 
        * src/lread.c (maybe_swap_for_eln): Rename el_name -> src_name as
@@ -73450,7 +73450,7 @@
 
 2020-08-11  Paul Eggert  <eggert@cs.ucla.edu>
 
-       pdumper speed tweeks for hash tables
+       pdumper speed tweaks for hash tables
 
        * src/pdumper.c (dump_queue_empty_p): Avoid unnecessary call
        to Fhash_table_count on a known hash table.
@@ -77752,7 +77752,7 @@
 
 2020-06-22  Andrea Corallo  <akrl@sdf.org>
 
-       Handle correctly pure delaration specifier.
+       Handle correctly pure declaration specifier.
 
        * lisp/emacs-lisp/comp.el (comp-func): New slot 'pure'.
        (comp-spill-decl-spec): New function.
@@ -81415,7 +81415,7 @@
 
 2020-05-14  Andrea Corallo  <akrl@sdf.org>
 
-       Dump log and intemediate GCC IRs only at comp-debug 3
+       Dump log and intermediate GCC IRs only at comp-debug 3
 
        * src/comp.c (Fcomp__init_ctxt): Increase threshold for dumping
        really everything to 'comp-debug' 3.
@@ -84459,7 +84459,7 @@
        either be encoding a string without NL, or decoding without CR.
 
        * src/coding.c (string_ascii_p): Revert to a pure predicate.
-       (code_convert_string): Fix logic.  Don't use uninitialised
+       (code_convert_string): Fix logic.  Don't use uninitialized
        ascii_p (removed).  Use memchr to detect CR or LF in string when needed.
        * test/src/coding-tests.el (coding-nocopy-ascii):
        Update tests to include encodings with explicit EOL conversions.
@@ -86579,7 +86579,7 @@
 
        Merge remote-tracking branch 'savannah/master' into HEAD
 
-       * Fix regexp instroduced by f055f52321
+       * Fix regexp introduced by f055f52321
 
 2020-03-09  Paul Eggert  <eggert@cs.ucla.edu>
 
@@ -86613,7 +86613,7 @@
 
        * lisp/term/rxvt.el: Enable backeted paste and window title
 
-       rxvt-unicode uses the same escape sequences as xterm so just re-use
+       rxvt-unicode uses the same escape sequences as xterm so just reuse
        the xterm functions to enable them.  The `xterm-rxvt-function-map`
        keymap already has
 
@@ -94009,7 +94009,7 @@
        Fix an error in tramp-sh-handle-make-process.  Don't merge with master
 
        * lisp/net/tramp-sh.el (tramp-sh-handle-make-process): Don't use heredoc
-       script whent the argument contains a string.
+       script when the argument contains a string.
 
 2021-02-03  Stefan Kangas  <stefan@marxist.se>
 
@@ -97511,7 +97511,7 @@
 
        * lisp/subr.el (cancel-change-group): Fix bug#39680
 
-       Don't re-use an existing `pending-undo-list` even if (eq last-command 
'undo)
+       Don't reuse an existing `pending-undo-list` even if (eq last-command 
'undo)
        since there might have been changes to the buffer since that `undo` 
command
        and the `pending-undo-list` can hence be invalid for the current
        buffer contents.
@@ -110510,7 +110510,7 @@
 
 2019-10-01  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Make the help page mention the customizeable global mode variable
+       Make the help page mention the customizable global mode variable
 
        * lisp/help-fns.el (help-fns--customize-variable): Factor out into
        own function for reuse.
@@ -117135,7 +117135,7 @@
        Use timer-convert with t rather than doing it by hand.
        * src/timefns.c (time_hz_ticks, time_form_stamp, lisp_time_form_stamp):
        Remove; no longer needed.
-       (decode_lisp_time): Rturn the form instead of having a *PFORM arg.
+       (decode_lisp_time): Return the form instead of having a *PFORM arg.
        All uses changed.
        (time_arith): Just return TICKS if HZ is 1.
        (Fencode_time): Remove argument FORM.  All callers changed.
@@ -131090,7 +131090,7 @@
        Make shr-rescale-image respect get-buffer-window again
 
        * lisp/net/shr.el (shr-rescale-image): Partially revert previous
-       change -- ressurrect the check for `get-buffer-window'.
+       change -- resurrect the check for `get-buffer-window'.
 
 2019-05-16  Ivan Shmakov  <ivan@siamics.net>
 
@@ -135103,7 +135103,7 @@
        (help-fns--var-ignored-local, help-fns--var-file-local)
        (help-fns--var-watchpoints, help-fns--var-obsolete)
        (help-fns--var-alias, help-fns--var-bufferlocal): New functions,
-       extacted from describe-variable.
+       extracted from describe-variable.
        (describe-variable): Run help-fns-describe-variable-functions instead.
 
 2019-04-12  Glenn Morris  <rgm@gnu.org>
@@ -163190,7 +163190,7 @@
        Quieten eshell compilation
 
        * lisp/eshell/em-tramp.el: Require esh-cmd.
-       * lisp/eshell/esh-ext.el: Requie esh-io at runtime too.
+       * lisp/eshell/esh-ext.el: Require esh-io at runtime too.
 
 2018-02-28  Glenn Morris  <rgm@gnu.org>
 
@@ -164098,7 +164098,7 @@
        (server-socket-dir): Compute socket dir from
        `get-external-sockname'.
        (server-start): Don't check for existing server when an
-       uninitialised external socket has been passed to Emacs.
+       uninitialized external socket has been passed to Emacs.
        * src/emacs.c: (main): Obtain socket name via getsockname and pass
        to `init_process_emacs'.
        * src/lisp.h: (init_process_emacs): Add second parameter.
@@ -165010,7 +165010,7 @@
 
        Merge from origin/emacs-26
 
-       6415b2d Allow read-passwd to hide characters inserted by C-y.  (Secur...
+       6415b2d Allow read-passwd to hide characters inserted by C-y.  
(Secure...
        8cb4ffb * etc/PROBLEMS: Document issues with double-buffering.  (Bug#...
        fd10070 * lisp/window.el (window-largest-empty-rectangle): Fix grammar.
        e1a4403 Minor changes in the Emacs manual
@@ -165500,7 +165500,7 @@
        1fc98ed073 ; Spelling fix
        bb396a369c Update Org to v9.1.6
        fa582153f7 Use text-pixels values only when saving framesets (Bug#30141)
-       6b01b9475d Minor improvement in section "Pages" of the usere manual
+       6b01b9475d Minor improvement in section "Pages" of the user manual
        e8c8bd3de2 Minor improvements in user manual
        26b8b92e63 Improve the "Mark" chapter of the user manual
        759569fe40 Improve the "Buffers" chapter of the user manual
@@ -167643,7 +167643,7 @@
 
 2017-12-12  Glenn Morris  <rgm@gnu.org>
 
-       Fix gitmerge handling of automatic conflict reslution
+       Fix gitmerge handling of automatic conflict resolution
 
        * admin/gitmerge.el (gitmerge-resolve): Reenable NEWS handling.
        (gitmerge-resolve-unmerged): Commit after successful resolution.
@@ -172441,11 +172441,11 @@
 
        * src/window.c (Fset_window_margins, Fset_window_fringes)
        (Fset_window_scroll_bars): In doc-strings tell that a window
-       must be large enough to accommodate fringes, sroll bars and
+       must be large enough to accommodate fringes, scroll bars and
        margins of the desired size.
        * doc/lispref/display.texi (Fringe Size/Pos, Scroll Bars)
        (Display Margins): Tell that windows must be large enough to
-       accommodate fringes, sroll bars and margins of the desired
+       accommodate fringes, scroll bars and margins of the desired
        size.
 
 2019-03-10  Eli Zaretskii  <eliz@gnu.org>
@@ -175963,7 +175963,7 @@
        Save the server alias on reconnect (Bug#29657)
 
        rcirc does not retain the server alias on reconnect.  As a result, rcirc
-       fails to re-use server and channel buffers when an alias is used.  
Further
+       fails to reuse server and channel buffers when an alias is used.  
Further
        problems may ensue when aliases are used to differentiate multiple
        connections to the same host, for example when using a single IRC 
bouncer
        or proxy to connect to multiple IRC networks.
@@ -180914,7 +180914,7 @@
 
 2018-01-21  Eli Zaretskii  <eliz@gnu.org>
 
-       Minor improvement in section "Pages" of the usere manual
+       Minor improvement in section "Pages" of the user manual
 
        * doc/emacs/text.texi (Pages): Improve wording.  Suggested by Will
        Korteland <emacs-devel@korte.land> in emacs-manual-bugs@gnu.org.
@@ -184512,7 +184512,7 @@
        * src/lisp.h (GCALIGNMENT): Change it back to a macro
        that expands to a literal integer constant, for older GCC.
        I had mistakenly thought that only MSVC had the problem.
-       Problem repored by Eli Zaretskii (Bug#29040#69).
+       Problem reported by Eli Zaretskii (Bug#29040#69).
 
 2017-11-03  Paul Eggert  <eggert@cs.ucla.edu>
 
@@ -186856,7 +186856,7 @@
        * doc/misc/flymake.texi (Overview of Flymake): Rewrite a bit.
        (Installing Flymake): Mostly scratch. Flymake comes with Emacs.
        (Running the syntax check): Simplify.
-       (Viewing error messages): Dekete,
+       (Viewing error messages): Delete.
        (Syntax check statuses): Rewrite.
        (Troubleshooting): Simplify.
        (Customizable variables): Rewrite.
@@ -188461,7 +188461,7 @@
        Loosen strict parsing requirement for desktop files
 
        There are other desktop-looking files, for instance those having to do
-       with MIME typess, that would benefit from being able to be read by this
+       with MIME types, that would benefit from being able to be read by this
        function.  It helps to have some flexibility.
        * lisp/xdg.el (xdg-desktop-read-file): Remove an error condition.
        * test/lisp/xdg-tests.el: Remove a test.
@@ -219622,7 +219622,7 @@
        for 0x80 ⪬ c < 0x100.  In other words, the loop never executes for
        c ≥ 0x80 and RE_CHAR_TO_MULTIBYTE call is unnecessary for c < 0x80.
 
-       * src/regex.c (regex_compile): Simplyfy a for loop by eliminating
+       * src/regex.c (regex_compile): Simplify a for loop by eliminating
        dead iterations and unnecessary macro calls.
 
 2016-09-08  Michal Nazarewicz  <mina86@mina86.com>
@@ -229115,7 +229115,7 @@
        6da3a6d Port to strict C99 offsetof
        de7601f Port to GTK with strict C11 compiler
        658aa2d Port to GTK with strict C99 compiler
-       1df7173 Avoid screen artifacts with new OS X visible bell after scrol...
+       1df7173 Avoid screen artifacts with new OS X visible bell after 
scroll...
        7a2edd3 Merge branch 'emacs-25' of git.sv.gnu.org:/srv/git/emacs into...
        dca240a Suppress some Tramp tests for OSX, do not merge with master
        9094304 * lisp/progmodes/xref.el (xref-buffer-name, xref--window): Mo...
@@ -233746,7 +233746,7 @@
 
        ee73997 Make erc work better when encountering unknown prefix chars
        b99141d Make erc completion case-insensitive again
-       66c4620 Make complection in erc use consistent casing
+       66c4620 Make completion in erc use consistent casing
        8c562b2 Make /QUIT in erc more robust
        d93d2c5 Make tracking faces in Emacs work more reliably
        af6ab7e Make shr not bug out on images on non-graphical displays
@@ -234944,7 +234944,7 @@
        (rng-complete-attribute-value): Don't perform completion, but return
        completion data instead.
        (rng-complete-qname-function, rng-generate-qname-list): Add a few
-       arguments, previously passed via dynamic coping.
+       arguments, previously passed via dynamic copying.
        (rng-strings-to-completion-table): Rename from
        rng-strings-to-completion-alist.  Don't return an alist.  Don't both
        sorting and uniquifying.
@@ -235280,7 +235280,7 @@
        d400753 * src/buffer.c: Stick with ASCII in doc string.
        221240c Reword transient-mark-mode doc string
        977d3ea Update doc string of 'selective-display'
-       229c3fa Make C++ buffers writeable when writing their initial text
+       229c3fa Make C++ buffers writable when writing their initial text
                properties.
        f5c762c Additional changes for "make check-expensive"
        1729cf3 ; * admin/MAINTAINERS: Remove myself.
diff --git a/ChangeLog.4 b/ChangeLog.4
index 24afabdbbb1..50fbbaa64cf 100644
--- a/ChangeLog.4
+++ b/ChangeLog.4
@@ -374,7 +374,7 @@
        Ensure ucs-names is consistent with Unicode names
 
        * lisp/international/mule-cmds.el (ucs-names): Skip adding an old-name
-       if it conflicts with the offical name of a codepoint.  Adjust the
+       if it conflicts with the official name of a codepoint.  Adjust the
        ranges iterated over to account for new Unicode codepoints.
        * test/lisp/international/mule-tests.el
        (mule-cmds-tests--ucs-names-old-name-override,
@@ -1705,7 +1705,7 @@
        (tramp-archive-test47-auto-load): Adapt test.
 
        * test/lisp/net/tramp-tests.el (tramp-display-escape-sequence-regexp):
-       Dont't declare.
+       Don't declare.
        (tramp-action-yesno): Suppress run in tests.
        (tramp-test02-file-name-dissect):
        (tramp-test02-file-name-dissect-simplified)
@@ -2155,7 +2155,7 @@
        selection from hanging owner, we will proceed to take ownership of the
        selection as normal, resolving the problem.
 
-       (One example of a selction owner that might not be responding to
+       (One example of a selection owner that might not be responding to
        selection requests is another instance of Emacs itself; while Emacs is
        blocked in call-process or Lisp execution, it currently does not
        respond to selection requests.)
@@ -3050,7 +3050,7 @@
        Revert changes to the order in which package descs are loaded
 
        * lisp/emacs-lisp/package.el (package-load-all-descriptors):  Remove
-       NOSORT argument to 'directory-files', reverting back to the behaviour
+       NOSORT argument to 'directory-files', reverting back to the behavior
        as of Emacs 28.  (Bug#63757)
 
 2023-06-04  Spencer Baugh  <sbaugh@janestreet.com>
@@ -3233,7 +3233,7 @@
        (plstore-save, plstore--encode, plstore--decode)
        (plstore--write-contents-functions, plstore-mode-decoded)
        (plstore-mode): Brush up doc strings and documentation in general.
-       Fix terminology, in particular spurious occurences of all uppercase
+       Fix terminology, in particular spurious occurrences of all uppercase
        "PLSTORE".  (Bug#63627)
 
 2023-05-31  Jens Schmidt  <jschmidt4gnu@vodafonemail.de>
@@ -4198,7 +4198,7 @@
        Prevent generating empty autoload files
 
        * lisp/emacs-lisp/loaddefs-gen.el (loaddefs-generate): Remove
-       optimisation that would mistakenly discard old loaddefs in case a file
+       optimization that would mistakenly discard old loaddefs in case a file
        was not modified by EXTRA-DATA is non-nil.  (Bug#62734)
 
 2023-04-30  Stefan Monnier  <monnier@iro.umontreal.ca>
@@ -5415,7 +5415,7 @@
 
 2023-03-29  Andrea Corallo  <akrl@sdf.org>
 
-       Comp fix calls to redefined primtives with op-bytecode (bug#61917)
+       Comp fix calls to redefined primitives with op-bytecode (bug#61917)
 
                * test/src/comp-tests.el (61917-1): New test.
                * src/comp.c (syms_of_comp): New variable.
@@ -5453,7 +5453,7 @@
 
 2023-03-28  Andrea Corallo  <akrl@sdf.org>
 
-       Revert "Comp fix calls to redefined primtives with op-bytecode 
(bug#61917)"
+       Revert "Comp fix calls to redefined primitives with op-bytecode 
(bug#61917)"
 
        This reverts commit 263d6c38539691c954f4c3057cbe8d5468499b91.
 
@@ -5791,10 +5791,10 @@
 
 2023-03-20  Andrea Corallo  <akrl@sdf.org>
 
-       Comp fix calls to redefined primtives with op-bytecode (bug#61917)
+       Comp fix calls to redefined primitives with op-bytecode (bug#61917)
 
        * lisp/emacs-lisp/comp.el (comp-emit-set-call-subr): Fix compilation
-       of calls to redefined primtives with dedicated op-bytecode.
+       of calls to redefined primitives with dedicated op-bytecode.
        * test/src/comp-tests.el (61917-1): New test.
 
 2023-03-20  Robert Pluim  <rpluim@gmail.com>
@@ -5914,7 +5914,7 @@
        CC Mode: Eliminate duplicate function c-list-of-strings
 
        Replace it with the existing c-string-list-p.  Also put an autoload 
cookie in
-       front of c-string-list-p so that it will not be signalled as undefined 
by
+       front of c-string-list-p so that it will not be signaled as undefined by
        loaddefs.el.
 
        lisp/progmodes/cc-vars.el (c-string-list-p): Make this autoload.
@@ -5932,7 +5932,7 @@
        (c-font-lock-extra-types, c++-font-lock-extra-types)
        (objc-font-lock-extra-types, java-font-lock-extra-types)
        (idl-font-lock-extra-types, pike-font-lock-extra-types): Add a :safe 
entry
-       into each of thes defcustoms for c-list-of-string.
+       into each of these defcustoms for c-list-of-string.
        (Top level): Add an autoload entry for each of the above.
 
 2023-03-18  Robert Pluim  <rpluim@gmail.com>
@@ -5955,7 +5955,7 @@
 
        Enhance section about troubleshooting in Eglot manual.
 
-       * doc/misc/eglot.texi (Troubleshooting Eglot): Parially rewrite.
+       * doc/misc/eglot.texi (Troubleshooting Eglot): Partially rewrite.
 
 2023-03-17  João Távora  <joaotavora@gmail.com>
 
@@ -5965,8 +5965,8 @@
        Before this change, it would only work if the user happened to have
        manually activated it before with 'yas-global-mode' or somesuch.
 
-       This makes Eglot's Yasnippet-activating behaviour similar to its
-       Flymake-activating behaviour.
+       This makes Eglot's Yasnippet-activating behavior similar to its
+       Flymake-activating behavior.
 
        * lisp/progmodes/eglot.el (eglot-client-capabilities): Consult
        eglot--stay-out-of.
@@ -6405,7 +6405,7 @@
 
 2023-03-09  João Távora  <joaotavora@gmail.com>
 
-       Autoload Eglot helper funtion eglot--debbugs-or-github-bug-uri
+       Autoload Eglot helper function eglot--debbugs-or-github-bug-uri
 
        This isn't a typical autoload: the progn block is plced in the
        autoloads file, but the eglot.el file itself isn't loaded as a result
@@ -6619,7 +6619,7 @@
 
        For example, in the 'buffer' category, the default value has the
        styles list '(basic substring)'.  This means that if a pattern matches
-       accoring to the 'basic' style, 'substring' will not be tried.  And
+       according to the 'basic' style, 'substring' will not be tried.  And
        neither will 'completion-styles' which in Fido mode's case happens to
        be 'flex'.
 
@@ -6635,7 +6635,7 @@
        * Fix `emacs-lisp-native-compile-and-load' for (bug#61917)
 
        * lisp/progmodes/elisp-mode.el (emacs-lisp-native-compile-and-load):
-       Don't load if no compialtion happened.
+       Don't load if no compilation happened.
 
 2023-03-06  Andrea Corallo  <akrl@sdf.org>
 
@@ -6750,7 +6750,7 @@
        "unspoffing" HOME just for the invocations of LSP server but it
        stopped working a while back.  So make it more robust.
 
-       Eventually, we'll want to decide wether these local servers should be
+       Eventually, we'll want to decide whether these local servers should be
        considered in 'make check' runs at all, or whether there is a way to
        use them with a spoofed HOME.
 
@@ -6835,7 +6835,7 @@
        Fix go-ts-mode multi-line string indentation (bug#61923)
 
        * lisp/progmodes/go-ts-mode.el:
-       (go-ts-mode--indent-rules): Add indent rule for multi-line sting.
+       (go-ts-mode--indent-rules): Add indent rule for multi-line string.
 
 2023-03-03  João Távora  <joaotavora@gmail.com>
 
@@ -6935,7 +6935,7 @@
 
        Originally our c-ts-mode--anchor-prev-sibling only specially handled
        labeled_statements, now we add special case for preproc in the similar
-       fasion: instead of using the preproc directive as anchor, use the last
+       fashion: instead of using the preproc directive as anchor, use the last
        statement in that preproc as the anchor. Thus effectively ignore the
        preproc.
 
@@ -6988,7 +6988,7 @@
        ([XwWebView initWithFrame:configuration:xwidget:])
        (nsxwidget_init):  Fixed memory leaks: when sending an alloc
        message to an object, send an autorelease message to any objects
-       we won't explictly release.
+       we won't explicitly release.
        ([XwWebView webView:didFinishNavigation:]): Second string to
        store in 'store_xwidget_event_string' is "load finished" rather
        than empty string.
@@ -7658,7 +7658,7 @@
        Eglot doesn't always show the LSP :label property of a CompletionItem
        in the completion candidates.  That is because label is sometimes not
        what should be inserted in the buffer in the end, the :insertText
-       property supercedes it.
+       property supersedes it.
 
        But the label is usually more suitable for display nevertheless and if
        the LSP CompletionItem contains either a snippet or a textEdit, it's
@@ -7720,7 +7720,7 @@
        occurs.  This is a much simpler mode of operation which may avoid
        problems, but is also likely much slower in large buffers.
 
-       Also, because the inlay feature is probably visually suprising to
+       Also, because the inlay feature is probably visually surprising to
        some, it is turned OFF by default, which is not the usual practice of
        Eglot (at least not when the necessary infrastructure is present).
        This decision may be changed soon.  Here's a good one-liner for
@@ -7731,7 +7731,7 @@
        I haven't tested inlay hints extensively across many LSP servers, so I
        would appreciate any testing, both for functional edge cases and
        regarding performance.  There are possibly more optimization
-       oportunities in the "lazy" mode of operation, like more aggressively
+       opportunities in the "lazy" mode of operation, like more aggressively
        deleting buffer overlays that are not in visible parts of the buffer.
 
        Though I ended up writing this one from scratch, I want to thank
@@ -7803,9 +7803,9 @@
 
        In that commit, I did what many longstanding issues and users were
        suggesting and removed Eglot's override of two Eldoc user
-       configuration varibles.
+       configuration variables.
 
-       I verified that Eglot's behaviour would stay mostly unaltered but my
+       I verified that Eglot's behavior would stay mostly unaltered but my
        tests were very incomplete.  In short there is no way that Eglot can
        work acceptably with the default setting of
        'eldoc-documentation-strategy', which is
@@ -8208,7 +8208,7 @@
        Fix 'display-buffer-use-least-recent-window'
 
        * src/window.c (Fwindow_use_time): Doc fix.
-       (Fwindow_bump_use_time): Bump use time of the seleceted window as
+       (Fwindow_bump_use_time): Bump use time of the selected window as
        well.  Doc fix.
 
        * lisp/window.el (display-buffer-avoid-small-windows): Remove.
@@ -8478,7 +8478,7 @@
 
 2023-02-16  Philip Kaludercic  <philipk@posteo.net>
 
-       Attempt to recognise if a VC package has no Elisp files
+       Attempt to recognize if a VC package has no Elisp files
 
        * lisp/emacs-lisp/package-vc.el (package-vc-non-code-file-names): Add
        new variable used to avoid false-positives.
@@ -8792,7 +8792,7 @@
        package specifications have been having issues with package-vc, when
        toggle-on-error is enabled.  In their case, package-vc would raise an
        error in its first invocation, but it would go on working normally
-       afterwards.  As this behaviour is confusing and the user can't do much
+       afterwards.  As this behavior is confusing and the user can't do much
        about a missing elpa-packages.eld to begin with, we satisfy ourselves
        with printing out a message and continuing on.
 
@@ -10316,7 +10316,7 @@
        Fix typo in c-ts-mode (bug#60932)
 
        * lisp/progmodes/c-ts-mode.el (c-ts-mode-indent-block-type-regexp):
-       enumerator, not enumeratior.
+       enumerator, not enumerator.
 
 2023-01-20  Mike Kupfer  <kupfer@rawbw.com>
 
@@ -11160,7 +11160,7 @@
        (treesit_load_language):
        (Ftreesit_pattern_expand):
        (Ftreesit_query_expand):
-       (treesit_eval_predicates): Use new varaibles.
+       (treesit_eval_predicates): Use new variables.
 
        (treesit_check_buffer_size):
        (treesit_compose_query_signal_data):
@@ -11899,7 +11899,7 @@
 
        * lisp/progmodes/ruby-ts-mode.el
        (ruby-ts-add-log-current-function): Fix the case when point is
-       between two methods.  'treesit-node-at' returs the 'def' node of
+       between two methods.  'treesit-node-at' returns the 'def' node of
        the method after point in such case, so it behaved like point was
        inside the method below.
 
@@ -12575,7 +12575,7 @@
 
        * doc/lispref/modes.texi (Imenu): Add manual.
        * doc/lispref/parsing.texi (Tree-sitter major modes): Update manual.
-       * lisp/treesit.el (treesit-simple-imenu-settings): New varaible.
+       * lisp/treesit.el (treesit-simple-imenu-settings): New variable.
        (treesit--simple-imenu-1)
        (treesit-simple-imenu): New functions.
        (treesit-major-mode-setup): Setup Imenu.
@@ -12840,7 +12840,7 @@
        (treesit--top-level-defun): Generalize into treesit--top-level-thing.
        (treesit--navigate-defun): Generalize into treesit--navigate-thing.
        (treesit-thing-at-point): Generalized from treesit-defun-at-point.
-       (treesit-defun-at-point): Use treesit-thing-at-point to do tht work.
+       (treesit-defun-at-point): Use treesit-thing-at-point to do the work.
 
 2022-12-25  Philip Kaludercic  <philipk@posteo.net>
 
@@ -13035,7 +13035,7 @@
        One way to solve it is to go back up the tree if we are at a leaf node
        and still haven't matched the target node.  That's too ugly and
        finicky so I resorted to recursion.  Now one more functions will
-       return give up (treesit_node_parent) if we are in a werid parse tree
+       return give up (treesit_node_parent) if we are in a weird parse tree
        that is super deep.  But since we already kind of give up on this kind
        of parse trees (bug#59426), it doesn't really hurt.
 
@@ -13287,7 +13287,7 @@
 
 2022-12-21  Andrea Corallo  <akrl@sdf.org>
 
-       * Invoke spawed Emacs processes with '-Q' when native compiling 
(bug#60208)
+       * Invoke spawned Emacs processes with '-Q' when native compiling 
(bug#60208)
 
        * lisp/emacs-lisp/comp.el (comp-final): Invoke spawned Emacs with '-Q'.
        (comp-run-async-workers): Likewise.
@@ -13455,7 +13455,7 @@
        Repair setopt test after error demotion to warning
 
        * test/lisp/cus-edit-tests.el (test-setopt):
-       Check for a warrning instead of an error in attempt to call `setopt`
+       Check for a warning instead of an error in attempt to call `setopt`
        with a value that does not match the declared type (bug#60162).
 
 2022-12-18  Dmitry Gutov  <dgutov@yandex.ru>
@@ -13523,13 +13523,13 @@
 
 2022-12-18  Philip Kaludercic  <philipk@posteo.net>
 
-       * lisp/cus-edit.el (setopt--set): Warn instead of rasing an error
+       * lisp/cus-edit.el (setopt--set): Warn instead of raising an error
 
        (Bug#60162)
 
 2022-12-18  Philip Kaludercic  <philipk@posteo.net>
 
-       Allow customising windmove user options with an empty prefix
+       Allow customizing windmove user options with an empty prefix
 
        * lisp/windmove.el (windmove--default-keybindings-type): Handle nil
        as a prefix value.  (Bug#60161)
@@ -13676,7 +13676,7 @@
        Add treesit_assume_true and treesit_cursor_helper
 
        This is part 1 of the change to change node API to cursor API.  See
-       the second part for more detail.  (I splitted the change to make the
+       the second part for more detail.  (I split the change to make the
        diff more sane.)
 
        * src/treesit.c (treesit_assume_true)
@@ -13860,7 +13860,7 @@
 
 2022-12-16  Eli Zaretskii  <eliz@gnu.org>
 
-       Revert "Elide broken but unnecessary `if` optimisations"
+       Revert "Elide broken but unnecessary `if` optimizations"
 
        This reverts commit 13aa376e93564a8cf2ddbbcf0968c6666620db89.
 
@@ -13874,7 +13874,7 @@
        This reverts commit f4b430140f0866f98bbf18b7094348dc64032813.
 
        Please don't install anything on the release branch that is not
-       strictly necessary fro Emacs 29.
+       strictly necessary for Emacs 29.
 
 2022-12-16  Mattias Engdegård  <mattiase@acm.org>
 
@@ -13896,7 +13896,7 @@
 
 2022-12-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Elide broken but unnecessary `if` optimisations
+       Elide broken but unnecessary `if` optimizations
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-if):
        Remove explicit clauses purposing to simplify
@@ -14026,7 +14026,7 @@
        1. the client code invoked by its jsonrpc--connection-receive inside
           the process filter callee immediately sends follow-up input to
           process within the same Lisp stack.  This is a common scenario,
-          especially during LSP initialiation sequence used by Eglot, a
+          especially during LSP initialization sequence used by Eglot, a
           jsonrpc.el client.
 
        2. that follow-up message is large enough for process-send-string to
@@ -14442,7 +14442,7 @@
 
        * lisp/emacs-lisp/shortdoc.el (shortdoc--display-function):
        If the parameter of :eval is a string then read, evaluate and print
-       the result.  This was always the intention and is documented behaviour.
+       the result.  This was always the intention and is documented behavior.
 
 2022-12-14  Michael Albinus  <michael.albinus@gmx.de>
 
@@ -14560,7 +14560,7 @@
 
        This new set of functions (and tests) should eliminate
        defun-navigation bugs and limitations we currently have.  This commit
-       doesn't change any existing bahavior: treesit-beginning/end-of-defun
+       doesn't change any existing behavior: treesit-beginning/end-of-defun
        and friends are unchanged.  The plan is to later switch gear and
        replace the current functions with the new ones introduced in this
        change.
@@ -14777,7 +14777,7 @@
        Eglot: allow skipping compile-time warnings about LSP interfaces
 
        * lisp/progmodes/eglot.el (eglot-strict-mode): Add 
'no-unknown-interfaces'.
-       (eglot--check-object): Honour new eglot-strict-mode value.
+       (eglot--check-object): Honor new eglot-strict-mode value.
 
 2022-12-11  Yuan Fu  <casouri@gmail.com>
 
@@ -15023,7 +15023,7 @@
 
        Bring back the project--value-in-dir logic
 
-       Essentialy revert commit 2389158a31b4a12, restoring the changes
+       Essentially revert commit 2389158a31b4a12, restoring the changes
        and fixing the conflicts.  Motivated by the problem brought up in
        bug#59722 (behavior of project-find-files/regexp when switching
        projects).  We should find other ways to improve performance.
@@ -15400,10 +15400,10 @@
        table.
 
        When the 'external' is in use, the usual styles configured by the user
-       or other in 'completion-styles' are completely overriden.  This
+       or other in 'completion-styles' are completely overridden.  This
        relatively minor inconvenience is the price to pay for responsive
        completion where the full set of completion candidates doesn't need to
-       be transfered into Emacs's address space.
+       be transferred into Emacs's address space.
 
        * lisp/external-completion.el: New file.
 
@@ -15521,7 +15521,7 @@
 
 2022-12-06  Mattias Engdegård  <mattiase@acm.org>
 
-       Lisp reader undefined behaviour excision
+       Lisp reader undefined behavior excision
 
        * src/lread.c (read_bool_vector, skip_lazy_string):
        Replace `|` with `||` to explicitly introduce sequence points since
@@ -15668,7 +15668,7 @@
 
 2022-12-03  Mattias Engdegård  <mattiase@acm.org>
 
-       Speed up Unicode normalisation tests by a factor of 5
+       Speed up Unicode normalization tests by a factor of 5
 
        After this change, ucs-normalize-tests are still very slow but
        somewhat less disastrously so (from 100 to 20 min on this machine).
@@ -15828,10 +15828,10 @@
        be as correct as possible we enable using both.
 
        * lisp/progmodes/typescript-ts-mode.el
-       (typescript-ts-mode--indent-rules): Change to a function to accomodate
+       (typescript-ts-mode--indent-rules): Change to a function to accommodate
        the two languages.
        (typescript-ts-mode--font-lock-settings): Change to a function to
-       accomodate the two languages.
+       accommodate the two languages.
        (typescript-ts-base-mode): Parent mode for typescript-ts-mode
        and tsx-ts-mode.
        (typescript-ts-mode): Derive from typescript-ts-base-mode and
@@ -16842,7 +16842,7 @@
        reverting the current buffer.  It made working in remote buffers with
        enable-remote-dir-locals non-nil slower, which doesn't seem worth it
        for a minor improvement of an infrequent operation.  Also less
-       compexity overall.
+       complexity overall.
 
        * lisp/progmodes/project.el (project-try-vc, project-files)
        (project--vc-list-files, project-ignores, project-buffers):
@@ -16929,7 +16929,7 @@
 
        This fixes bug #59427.  We now handle correctly the case when a 
parenthesis
        follows the * which is ambiguously a multiplication or indirection 
operator.
-       Also, we don't recognise a type thus found as a found type - the 
evidence is
+       Also, we don't recognize a type thus found as a found type - the 
evidence is
        too weak.
 
        * lisp/progmodes/cc-engine.el (c-forward-decl-or-cast-1): Fix CASE 17.5 
as
@@ -17846,7 +17846,7 @@
        Previously applied heuristic 2 sometimes invalidates heuristic 1, add
        a guard so it doesn't.
 
-       The new function is just for clearity of the code and has nothing to
+       The new function is just for clarity of the code and has nothing to
        do with the change itself.
 
        * lisp/treesit.el (treesit--node-length): New function
@@ -18380,7 +18380,7 @@
 
        * test/lisp/simple-tests.el
        (simple-execute-extended-command--describe-binding-msg):
-       Bind text-quoting-style explicitly to ensure consistent behaviour
+       Bind text-quoting-style explicitly to ensure consistent behavior
        whether or not the test is run interactively.
 
 2022-11-18  Stefan Kangas  <stefankangas@gmail.com>
@@ -18531,7 +18531,7 @@
 
 2022-11-17  Philip Kaludercic  <philipk@posteo.net>
 
-       Fix the behaviour of 'byte-compile-ignore-files'
+       Fix the behavior of 'byte-compile-ignore-files'
 
        * lisp/emacs-lisp/bytecomp.el (byte-recompile-directory): Negate the
        'string-match-p' check.  (Bug#59139)
@@ -18694,7 +18694,7 @@
 
        * lisp/emacs-lisp/package-vc.el (package-vc-repository-store):
        Unmention 'package-vc--unpack'.
-       (package-vc-install): Unmention 'package-vc--guess-backend' in favour
+       (package-vc-install): Unmention 'package-vc--guess-backend' in favor
        of 'package-vc-heuristic-alist'.
 
 2022-11-17  Philip Kaludercic  <philipk@posteo.net>
@@ -18736,7 +18736,7 @@
        Mark 'package-vc-update' as interactive
 
        * lisp/emacs-lisp/package-vc.el (package-vc--sourced-packages-list):
-       Remove function in favour of 'package-vc--read-package-name'.
+       Remove function in favor of 'package-vc--read-package-name'.
        (package-vc--read-package-name):
        Extract out common functionality.
        (package-vc--read-package-desc): Add auxiliary function based on
@@ -18745,7 +18745,7 @@
        'package-vc--read-package-desc'.
        (package-vc-install): Use 'package-vc--read-package-desc'.
        (package-vc-checkout): Use 'package-vc--read-package-desc'.
-       (package-vc--read-pkg): Remove in favour of 
'package-vc--read-package-desc'.
+       (package-vc--read-pkg): Remove in favor of 
'package-vc--read-package-desc'.
        (package-vc-refresh): Use 'package-vc--read-package-desc'.
        (package-vc-prepare-patch): Use 'package-vc--read-package-desc'.
 
@@ -18779,7 +18779,7 @@
        Handle strings as keys in 'package-vc-ensure-packages'
 
        * lisp/emacs-lisp/package-vc.el (package-vc-ensure-packages): Inter
-       sting keys while processing 'package-vc-selected-packages'.
+       string keys while processing 'package-vc-selected-packages'.
 
        As requested by Rudolf Adamkovič.
 
@@ -20734,10 +20734,10 @@
 
        * doc/lispref/modes.texi (Parser-based Indentation): Update manual.
        * lisp/progmodes/js.el (js--treesit-indent-rules): Change all
-       occurance of ,js-indent-level to js-indent-level.
+       occurrence of ,js-indent-level to js-indent-level.
 
        * lisp/progmodes/ts-mode.el (ts-mode--indent-rules): Change all
-       occurance of ,ts-mode-indent-offset to ts-mode-indent-offset.
+       occurrence of ,ts-mode-indent-offset to ts-mode-indent-offset.
        * lisp/treesit.el (treesit-simple-indent-rules): Change docstring.
        (treesit-simple-indent): Allow offset to be a variable.
 
@@ -21031,7 +21031,7 @@
        Print "decrypted" rot13 text is buffer is read-only
 
        * lisp/rot13.el (rot13-region): Add fallback if buffer is read-only
-       * doc/emacs/rmail.texi (Rmail Rot13): Document new behaviour.
+       * doc/emacs/rmail.texi (Rmail Rot13): Document new behavior.
 
 2022-11-04  Philip Kaludercic  <philipk@posteo.net>
 
@@ -21315,7 +21315,7 @@
 
        * lisp/progmodes/js.el (js--treesit-font-lock-settings)
        * lisp/progmodes/ts-mode.el (ts-mode--font-lock-settings): Capture
-       commend and strings.  Add empty lines.
+       comment and strings.  Add empty lines.
 
 2022-11-03  Jim Porter  <jporterbugs@gmail.com>
 
@@ -21739,7 +21739,7 @@
 
 2022-11-01  Gerd Möllmann  <gerd@gnu.org>
 
-       Preven a buffer-overflow (bug#58850)
+       Prevent a buffer-overflow (bug#58850)
 
        * src/print.c (print_vectorlike): Don't use sprintf.
 
@@ -21831,7 +21831,7 @@
        * doc/lispref/modes.texi (Parser-based Font Lock): Reflect the change
        in manual.
        * lisp/font-lock.el (font-lock-fontify-syntactically-function): New
-       varaible.
+       variable.
        (font-lock-default-fontify-region): Call
        font-lock-fontify-syntactically-function rather.
        (font-lock-fontify-syntactically-region): Rename to
@@ -21984,7 +21984,7 @@
        Unmention :release-rev
        (package-vc-desc->spec): Fall back on other archives if a
        specification is missing.
-       (package-vc-main-file): Add new function, copying the behaviour of
+       (package-vc-main-file): Add new function, copying the behavior of
        elpa-admin.el.
        (package-vc-generate-description-file): Use 'package-vc-main-file'.
        (package-vc-unpack): Handle special value ':last-release'.
@@ -21996,7 +21996,7 @@
        * lisp/vc/vc.el (vc-default-last-change): Add default 'last-change'
        implementation.
 
-       This attempts to replicate the behaviour of elpa-admin.el's
+       This attempts to replicate the behavior of elpa-admin.el's
        "elpaa--get-last-release-commit".
 
 2022-10-30  Damien Cassou  <damien@cassou.me>
@@ -23428,10 +23428,10 @@
 
 2022-10-24  Mattias Engdegård  <mattiase@acm.org>
 
-       Fix regexp matching with atomic strings and optimised backtracking
+       Fix regexp matching with atomic strings and optimized backtracking
 
        This bug occurs when an atomic pattern is matched at the end of
-       a string and the on-failure-keep-string-jump optimisation is
+       a string and the on-failure-keep-string-jump optimization is
        in effect, as in:
 
          (string-match "\\'\\(?:ab\\)*\\'" "a")
@@ -23533,7 +23533,7 @@
 
 2022-10-23  Yuan Fu  <casouri@gmail.com>
 
-       Change function signiture of treesit search functions
+       Change function signature of treesit search functions
 
        Justification: We want to make the SIDE argument in
        treesit-search-forward-goto optional, so I changed it to START.
@@ -23549,7 +23549,7 @@
        will probably be used more frequently than ALL anyway.
 
        * doc/lispref/parsing.texi (Retrieving Node): Resolve FIXME and update
-       function signitures.
+       function signatures.
        * lisp/treesit.el (treesit-search-forward-goto): Change SIDE to
        START, swap BACKWARD and ALL.
        (treesit-beginning-of-defun)
@@ -23581,7 +23581,7 @@
 
 2022-10-23  Philip Kaludercic  <philipk@posteo.net>
 
-       ;Fix typo "pacakge" -> "package"
+       ; Fix typo for "package"
 
 2022-10-23  Philip Kaludercic  <philipk@posteo.net>
 
@@ -23595,7 +23595,7 @@
 
 2022-10-23  Philip Kaludercic  <philipk@posteo.net>
 
-       ;Fix typo "heusitic" -> "heuristic"
+       ; Fix typo for "heuristic"
 
 2022-10-23  Philip Kaludercic  <philipk@posteo.net>
 
@@ -24301,7 +24301,7 @@
        from an identifier before passing it to c-add-type.
        (c-forward-decl-or-cast-1): CASE 3: Do not recognize two consecutive
        identifiers as type + variable/function unless certain conditions are 
met.
-       CASE 10: Do not recognize the "type" as a found type unless certain 
condtions
+       CASE 10: Do not recognize the "type" as a found type unless certain 
conditions
        are met.  (Near end): Do not recognize the identifier in a cast as a 
type
        unless certain conditions are met.
 
@@ -24919,9 +24919,9 @@
 
        Delete the itree_null sentinel node, use NULL everywhere.
 
-       This effort caught a few (already commited) places that were
+       This effort caught a few (already committed) places that were
        dereferencing through ITREE_NULL in a confusing way.  It makes some
-       functions have to check for NULL in more places, but in my experinece
+       functions have to check for NULL in more places, but in my experience
        this is worth it from a code clarity point of view.
 
        In doing this I rewrote `interval_tree_remove` completely.  There
@@ -25979,7 +25979,7 @@
        * src/itree.c (itree_null): Statically initialize itree_null.parent to
        NULL.  It is never accessed.
        (null_is_sane): Assert parent == NULL.
-       (interval_tree_remove_fix): Remove unecessary assignments to parent
+       (interval_tree_remove_fix): Remove unnecessary assignments to parent
        from node->parent.  These were the last places itree_null.parent were
        read.
        (interval_tree_remove): Avoid an assignment to itree_null.parent
@@ -26142,7 +26142,7 @@
 
 2022-10-10  Yuan Fu  <casouri@gmail.com>
 
-       Improve treesit-search-forward-goto so it doens't stuck at EOF
+       Improve treesit-search-forward-goto so it doesn't stuck at EOF
 
        * lisp/treesit.el (treesit-search-forward-goto): Handle the edge case.
 
@@ -26198,7 +26198,7 @@
 
        Fix tree-sitter build script in admin/notes
 
-       * admin/notes/tree-sitter/build-module/README: Add explaination.
+       * admin/notes/tree-sitter/build-module/README: Add explanation.
        * admin/notes/tree-sitter/build-module/build.sh: change
        typescript to tsx.
 
@@ -26304,14 +26304,14 @@
        Remove redundant check of the `limit` value.
        (interval_node_init): Remove `begin` and `end` args.
        (interval_tree_insert): Mark it as static.
-       Assert that the new node's `otick` should already be uptodate and its
+       Assert that the new node's `otick` should already be up-to-date and its
        new parent as well.
        (itree_insert_node): New function.
        (interval_tree_insert_gap): Assert the otick of the removed+added nodes
-       were uptodate and mark them as uptodate again after adjusting
+       were up-to-date and mark them as up-to-date again after adjusting
        their positions.
        (interval_tree_inherit_offset): Check that the parent is at least as
-       uptodate as the child.
+       up-to-date as the child.
 
        * src/lisp.h (build_overlay): Move to `buffer.h`.
 
@@ -26336,7 +26336,7 @@
        * lisp/simple.el (execute-extended-command--shorter): Compute a
        complete list of `commandp' symbols once.  This significantly speeds
        up complicated cases while the slowdown of simple cases is still
-       accetable.
+       acceptable.
 
 2022-10-09  समीर सिंह Sameer Singh  <lumarzeli30@gmail.com>
 
@@ -26419,7 +26419,7 @@
 
 2022-10-08  Mattias Engdegård  <mattiase@acm.org>
 
-       Restrict string-lessp vectorisation to safe architectures
+       Restrict string-lessp vectorization to safe architectures
 
        * src/fns.c (HAVE_FAST_UNALIGNED_ACCESS): New.
        (Fstring_lessp): Only use word operations where safe, because string
@@ -27109,7 +27109,7 @@
        (interval_tree_propagate_limit): Use it.
        (null_is_sane): Remove `inline` annotation; it's not needed.
        (interval_tree_inherit_offset): Sanity check that `offset` is 0 when
-       `otick` is uptodate.  Skip the unneeded increments when the offset is 0.
+       `otick` is up-to-date.  Skip the unneeded increments when the offset is 
0.
        (interval_tree_insert_fix): Add sanity check that we indeed have 2 reds.
 
 2022-10-05  Po Lu  <luangruo@yahoo.com>
@@ -27258,7 +27258,7 @@
        Fix bug in "macintization" of x_draw_glyph_string
 
        * src/nsterm.m (ns_draw_stretch_glyph_string): Restore text decoration
-       drawing code ommitted during "macintization" to convert the X function
+       drawing code omitted during "macintization" to convert the X function
        into NS code.  Reported by Qiantan Hong <qthong@stanford.edu>.
 
 2022-10-04  Filipp Gunbin  <fgunbin@fastmail.fm>
@@ -27393,7 +27393,7 @@
 
        Merge from origin/emacs-28
 
-       a78af3018e * src/emacs.c (load_pdump): Propery handle case when execu...
+       a78af3018e * src/emacs.c (load_pdump): Properly handle case when 
execu...
 
        # Conflicts:
        #       src/emacs.c
@@ -27429,7 +27429,7 @@
 
 2022-10-04  Andreas Schwab  <schwab@linux-m68k.org>
 
-       * src/emacs.c (load_pdump): Propery handle case when executable
+       * src/emacs.c (load_pdump): Properly handle case when executable
        wasn't found.
 
 2022-10-04  Alan Mackenzie  <acm@muc.de>
@@ -27626,7 +27626,7 @@
 
        * src/xterm.c (x_handle_wm_state): New function.
        (handle_one_xevent): Handle window state changes in WM_STATE
-       messages, and use them for signalling deiconification.
+       messages, and use them for signaling deiconification.
        (bug#58164)
 
 2022-10-03  Stefan Kangas  <stefankangas@gmail.com>
@@ -28386,7 +28386,7 @@
        Rectify string= documentation
 
        * doc/lispref/strings.texi (Text Comparison): Describe the current
-       behaviour since about 20 years back.
+       behavior since about 20 years back.
 
 2022-09-30  Mattias Engdegård  <mattiase@acm.org>
 
@@ -28400,7 +28400,7 @@
        Speed up string-lessp further
 
        * src/fns.c (Fstring_lessp): Use the memcmp fast path for ASCII-only
-       multibyte strings as well.  Specialise loops on argument
+       multibyte strings as well.  Specialize loops on argument
        multibyteness.
 
 2022-09-30  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -28470,7 +28470,7 @@
 
        Remove the per-tree null node
 
-       "make check" shows 0 unexpcted.
+       "make check" shows 0 unexpected.
 
        * src/itree.h (itree_null): Declare extern.
        (ITREE_NULL): New macro
@@ -29344,7 +29344,7 @@
        "c++-or-c-but-not-both-at-once" server, this commit now breaks that
        person's configuration.
 
-       After analysing the entries of this variable, an educated guess was
+       After analyzing the entries of this variable, an educated guess was
        made that this situation is rare.  If it's not rare, then some change
        to the syntax of eglot-server-programs will have to ensue.
 
@@ -29902,7 +29902,7 @@
        variable.
        (c-after-change-mark-abnormal-strings): Set c-open-string-opener when an
        unbalanced string is detected.
-       (c-before-change): Initilize c-open-string-opener to nil, each buffer 
change.
+       (c-before-change): Initialize c-open-string-opener to nil, each buffer 
change.
        (c-electric-pair-inhibit-predicate): Use the value of 
c-open-string-opener to
        flag an unbalaced string rather than trying to calculate it again.
 
@@ -30203,7 +30203,7 @@
        Make bounding box of 'image-crop' more noticeable
 
        * lisp/image/image-crop.el (image-crop--crop-image-1): Darken the
-       selected region to make the bounding-box more noticable in images
+       selected region to make the bounding-box more noticeable in images
        which are mostly white (bug#58004).
 
 2022-09-23  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -30445,7 +30445,7 @@
        Work around rare crash when turning scroll wheel
 
        * src/xterm.c (handle_one_xevent): Don't allow devices to be
-       added twice handling hierarcy events.
+       added twice handling hierarchy events.
 
 2022-09-21  Sean Whitton  <spwhitton@spwhitton.name>
 
@@ -31133,7 +31133,7 @@
 
 2022-09-19  Po Lu  <luangruo@yahoo.com>
 
-       * Makefile.in: Readd warnings about "git clean -fdx"
+       * Makefile.in: Re-add warnings about "git clean -fdx"
 
 2022-09-19  Po Lu  <luangruo@yahoo.com>
 
@@ -34162,7 +34162,7 @@
 
        Fix (mostly multibyte) issues in sieve-manage.el (Bug#54154)
 
-       The managesieve protocol (s. RFC5804) requires support for (a sightly
+       The managesieve protocol (s. RFC5804) requires support for (a slightly
        restricted variant of) UTF-8 in script content and script names. This
        commit fixes/improves the handling of multibyte characters.
 
@@ -34210,7 +34210,7 @@
 
 2022-09-06  Kai Tetzlaff  <emacs@tetzco.de>
 
-       Improve robustnes of `sieve-manage-quit' in case of errors
+       Improve robustness of `sieve-manage-quit' in case of errors
 
        * lisp/net/sieve.el (sieve-manage-quit): Avoid killing buffers it's
        not supposed to touch (bug#54154).
@@ -34304,7 +34304,7 @@
        * lisp/ffap.el (find-file-at-point): Allow people to set
        ffap-file-finder again (bug#50279).
 
-       * lisp/ido.el (ido-everywhere): Add an interstitial to fulfil
+       * lisp/ido.el (ido-everywhere): Add an interstitial to fulfill
        ffap-file-handler semantics.
 
 2022-09-06  Stefan Kangas  <stefankangas@gmail.com>
@@ -35482,7 +35482,7 @@
        * lisp/t-mouse.el (gpm-mouse-tty-setup): New function.
        (gpm-mouse-mode): Use it as well as `tty-setup-hook`.
        * lisp/term/linux.el (terminal-init-linux): Remove gpm-specific code,
-       not neded any more.
+       not needed any more.
 
 2022-08-30  Gregory Heytings  <gregory@heytings.org>
 
@@ -36843,7 +36843,7 @@
 
 2022-08-21  Mattias Engdegård  <mattiase@acm.org>
 
-       Fix eshell-pipe-broken signalling
+       Fix eshell-pipe-broken signaling
 
        * lisp/eshell/esh-io.el (eshell-output-object-to-target):
        Second argument to `signal` should be a list.
@@ -36927,12 +36927,12 @@
 
 2022-08-21  Mattias Engdegård  <mattiase@acm.org>
 
-       Update function properties and optimisations
+       Update function properties and optimizations
 
        * lisp/emacs-lisp/byte-opt.el (byte-opt--bool-value-form):
-       Recognise boolean identity in aset, put, function-put and puthash.
+       Recognize boolean identity in aset, put, function-put and puthash.
        * lisp/emacs-lisp/byte-opt.el (byte-compile-trueconstp):
-       Mark more functins as non-nil-returning, including the new
+       Mark more functions as non-nil-returning, including the new
        pos-bol and pos-eol.
        * lisp/emacs-lisp/byte-opt.el (side-effect-free-fns):
        Mark pos-bol and pos-eol as side-effect-free.
@@ -37065,7 +37065,7 @@
 
 2022-08-19  Mattias Engdegård  <mattiase@acm.org>
 
-       Move `while` syntax check from optimiser to macroexpand
+       Move `while` syntax check from optimizer to macroexpand
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-while): Move check...
        * lisp/emacs-lisp/macroexp.el (macroexp--expand-all): ...here.
@@ -37226,7 +37226,7 @@
        python.el: Adjustments to Flymake backend
 
        * lisp/progmodes/python.el (python-flymake-command): Advertise
-       possiblity to use pylint.
+       possibility to use pylint.
        (python-flymake-command-output-pattern): Make compatible with recent
        versions of pyflakes.  (Bug#53913)
 
@@ -37477,7 +37477,7 @@
 
 2022-08-18  Mattias Engdegård  <mattiase@acm.org>
 
-       More non-nil-returning functions in source optimisation
+       More non-nil-returning functions in source optimization
 
        This change was partially generated and mechanically cross-validated
        with function type information from comp-known-type-specifiers in
@@ -37785,7 +37785,7 @@
 
 2022-08-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Improved `null` (alias `not`) optimisation
+       Improved `null` (alias `not`) optimization
 
        Take static boolean information of the argument into account.
 
@@ -37793,7 +37793,7 @@
 
 2022-08-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Improved `and` and `or` optimisation
+       Improved `and` and `or` optimization
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-and, byte-optimize-or):
        Rewrite.  Avoid branching on arguments statically known to be true or
@@ -37801,9 +37801,9 @@
 
 2022-08-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Improved `if` and `while` optimisation
+       Improved `if` and `while` optimization
 
-       Recognise some more special cases:
+       Recognize some more special cases:
 
          (if X nil t)      -> (not X)
          (if X t)          -> (not (not X))
@@ -38519,7 +38519,7 @@
 
        Make htmlfontify-version variable obsolete
 
-       * lisp/htmlfontify.el (htmlfontify-version): Make obolete.
+       * lisp/htmlfontify.el (htmlfontify-version): Make obsolete.
        (hfy-meta-tags): Don't use above obsolete variable.
 
 2022-08-13  Stefan Kangas  <stefan@marxist.se>
@@ -38545,7 +38545,7 @@
 
 2022-08-13  Po Lu  <luangruo@yahoo.com>
 
-       Prevent selection converter from signalling if buffer is narrowed
+       Prevent selection converter from signaling if buffer is narrowed
 
        * lisp/select.el (xselect-convert-to-string): If positions are
        outside the accessible portion of the buffer, don't return
@@ -38980,7 +38980,7 @@
 
        Add "send patches" note to package-vc TODO section
 
-       * package.el (describe-package-1): Add news if avaliable
+       * package.el (describe-package-1): Add news if available
 
        * package.el (package--get-activatable-pkg): Prefer source packages
 
@@ -39101,14 +39101,14 @@
 
 2022-08-10  Mattias Engdegård  <mattiase@acm.org>
 
-       Extend LAP optimisations to more operations
+       Extend LAP optimizations to more operations
 
        Extend the set of eligible opcodes for certain peephole
-       transformations, which then provide further optimisation
+       transformations, which then provide further optimization
        opportunities.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-lapcode):
-       Optimise empty save-current-buffer in the same way as we already
+       Optimize empty save-current-buffer in the same way as we already
        do for save-excursion and save-restriction.  This is safe
        because (save-current-buffer) is a no-op.
        (byte-compile-side-effect-and-error-free-ops): Add list3, list4 and
@@ -40884,7 +40884,7 @@
 
        * lisp/auth-source.el (auth-source-netrc-parse-all): New function
        (bug#56976).
-       (auth-source-netrc-parse): Partially revert behaviour in previous
+       (auth-source-netrc-parse): Partially revert behavior in previous
        change -- require :allow-null to match.
 
 2022-08-04  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -40900,7 +40900,7 @@
 
        * lisp/emacs-lisp/package.el
        (package-autoload-ensure-default-file): Don't warn about
-       soon-to-be obsolete functon.
+       soon-to-be obsolete function.
 
 2022-08-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -41190,7 +41190,7 @@
 
        Adjust src/Makefile.in comments about make-docfile
 
-       * src/Makefile.in ($(etc)/DOC): Remove comment aboout make-docfile
+       * src/Makefile.in ($(etc)/DOC): Remove comment about make-docfile
        being run twice (because it no longer is).
 
 2022-08-04  Po Lu  <luangruo@yahoo.com>
@@ -41244,7 +41244,7 @@
        Avoid redundant calls to XFlush in x_make_frame_visible
 
        * src/xterm.c (x_make_frame_visible): Keep track of whether or
-       not the output buffer was implictly flushed before issuing
+       not the output buffer was implicitly flushed before issuing
        XFlush.
 
 2022-08-03  Stefan Monnier  <monnier@iro.umontreal.ca>
@@ -41787,7 +41787,7 @@
        same key is specified twice.  (Bug#56873)
 
        * doc/lispref/keymaps.texi (Creating Keymaps): Document error
-       signaling behaviour.
+       signaling behavior.
 
        * test/src/keymap-tests.el (keymap-test-duplicate-definitions): Test
        duplicate definition detection.
@@ -42498,7 +42498,7 @@
        Remove loaddefs debug code
 
        * lisp/emacs-lisp/loaddefs-gen.el (loaddefs-generate--rubric):
-       Remove code inadvertantly checked in.
+       Remove code inadvertently checked in.
 
 2022-07-31  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -42829,7 +42829,7 @@
        Minor improvements to precision scroll interpolation
 
        * lisp/pixel-scroll.el (pixel-scroll-start-momentum): Bump GC
-       cons threshold temporarily.  This leads to a very noticable
+       cons threshold temporarily.  This leads to a very noticeable
        improvement to animation speed.
 
 2022-07-29  Po Lu  <luangruo@yahoo.com>
@@ -42954,7 +42954,7 @@
        (XTframe_up_to_date): Set FRAME_X_WAITING_FOR_DRAW if bumped.
        (handle_one_xevent): Handle frame drawn events.
 
-       * src/xterm.h (struct x_output): New fields for frame dirtyness
+       * src/xterm.h (struct x_output): New fields for frame dirtiness
        and vsync.
 
 2022-07-29  Gregory Heytings  <gregory@heytings.org>
@@ -43774,7 +43774,7 @@
 
 2022-07-25  Robert Pluim  <rpluim@gmail.com>
 
-       Make package-archives URL treatment slighty laxer
+       Make package-archives URL treatment slightly laxer
 
        'package-archives' URLs are expected to end in '/', but we can
        cater for people typoing that by using 'url-expand-file-name'.
@@ -44540,7 +44540,7 @@
 
        Merge from origin/emacs-28
 
-       ea44d7ddfc ; * lisp/mail/smtpmail.el (smtpmail-via-smtp): Explain wit...
+       ea44d7ddfc ; * lisp/mail/smtpmail.el (smtpmail-via-smtp): Explain 
with...
 
 2022-07-20  Po Lu  <luangruo@yahoo.com>
 
@@ -45294,7 +45294,7 @@
 
 2022-07-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise `append` calls
+       Optimize `append` calls
 
        Add the transforms
 
@@ -45317,7 +45317,7 @@
 
 2022-07-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Improved cons optimisation
+       Improved cons optimization
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-cons):
        Add the transform
@@ -45326,10 +45326,10 @@
 
 2022-07-16  Mattias Engdegård  <mattiase@acm.org>
 
-       Transform (list) -> nil in source optimiser
+       Transform (list) -> nil in source optimizer
 
-       This optimisation is already done in the code generator but performing
-       it at this earlier stage is a useful normalising step that uncovers
+       This optimization is already done in the code generator but performing
+       it at this earlier stage is a useful normalizing step that uncovers
        more opportunities.
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-list): New.
@@ -45702,7 +45702,7 @@
        (xref-backend-definitions): Complicate.
        (completion-category-overrides): Register a category and a style here.
        (completion-styles-alist): Add eglot--lsp-backend-style style
-       (eglot--lsp-backend-style-call): New funtion.
+       (eglot--lsp-backend-style-call): New function.
        (eglot--lsp-backend-style-all-completions): New function.
        (eglot--lsp-backend-style-try-completion): New function.
 
@@ -46131,7 +46131,7 @@
 
 2022-07-12  Mattias Engdegård  <mattiase@acm.org>
 
-       Better gomoku X colour with bright background
+       Better gomoku X color with bright background
 
        * lisp/play/gomoku.el (gomoku-X): Use blue rather than green for
        crosses on bright background for better legibility.
@@ -46155,7 +46155,7 @@
        * src/pgtkmenu.c (set_frame_menubar)
        * src/xdisp.c (update_menu_bar)
        * src/xmenu.c (set_frame_menubar): Remove calls to 
Qrecompute_lucid_menubar
-       contitional on Vlucid_menu_bar_dirty_flag.
+       conditional on Vlucid_menu_bar_dirty_flag.
 
 2022-07-12  Po Lu  <luangruo@yahoo.com>
 
@@ -46929,7 +46929,7 @@
        * src/dispextern.h (WITH_NARROWED_BEGV): New macro.
 
        * src/xdisp.c (get_narrowed_begv): New function.
-       (init_iterator): Initilize the 'narrowed_begv' field.
+       (init_iterator): Initialize the 'narrowed_begv' field.
        (back_to_previous_line_start, get_visually_first_element,
        move_it_vertically_backward): Use the new macro.
 
@@ -47342,7 +47342,7 @@
        * src/fns.c (concat_strings): Rename to...
        (concat_to_string): ...this.
        (concat): Split into concat_to_list and concat_to_vector.
-       (concat_to_list, concat_to_vector): New, specialised and
+       (concat_to_list, concat_to_vector): New, specialized and
        streamlined from earlier combined code.
        (concat2, concat3, Fappend, Fconcat, Fvconcat): Adjust calls.
 
@@ -48036,7 +48036,7 @@
 
 2022-07-05  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Documnt left/right mwheel events
+       Document left/right mwheel events
 
        * doc/lispref/commands.texi (Misc Events): Document left/right
        mwheel events (bug#41722).
@@ -48727,7 +48727,7 @@
 
 2022-07-03  Eli Zaretskii  <eliz@gnu.org>
 
-       Implement pseudo-value 'reset' of face attrributes
+       Implement pseudo-value 'reset' of face attributes
 
        * doc/lispref/display.texi (Face Attributes):
        * etc/NEWS: Document the new pseudo-value 'reset'.
@@ -49171,7 +49171,7 @@
 
 2022-07-01  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Make time-stamp-tests.el work in a Norwegian language enviroment
+       Make time-stamp-tests.el work in a Norwegian language environment
 
        The short version of names for days/month is not necessary the same as
        limiting the string with a #n operator.  For instance:
@@ -50159,7 +50159,7 @@
 
 2022-06-30  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Restore temp-buffer-resize-mode behaviour wrt. [back] buttons
+       Restore temp-buffer-resize-mode behavior wrt. [back] buttons
 
        * lisp/help.el (help--window-setup): If temp-buffer-resize-mode, do
        the window setup after adding [back] buttons (bug#56306).
@@ -50962,7 +50962,7 @@
 
 2022-06-26  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise away functions in for-effect context
+       Optimize away functions in for-effect context
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
        Turn functions into nil when compiled for-effect since they have no
@@ -50970,7 +50970,7 @@
        as the elimination of variable bindings.
        `unwind-protect` forms can be treated as plain function call at this
        point.  In particular, their unwind function argument should be
-       not optimised for effect since it's a function.
+       not optimized for effect since it's a function.
 
 2022-06-26  Stefan Monnier  <monnier@iro.umontreal.ca>
 
@@ -51141,7 +51141,7 @@
 
        * lisp/files.el (locate-user-emacs-file): Don't create HOME if it
        doesn't exist (bug#47298).  This returns us to Emacs 26.3
-       behaviour here.
+       behavior here.
 
 2022-06-26  Michael Albinus  <michael.albinus@gmx.de>
 
@@ -51524,7 +51524,7 @@
 
        Bytecode opcode comments update
 
-       This is a cosmetic change only; there is no change in behaviour.
+       This is a cosmetic change only; there is no change in behavior.
 
        * lisp/emacs-lisp/bytecomp.el:
        * src/bytecode.c (BYTE_CODES, exec_byte_code):
@@ -51999,7 +51999,7 @@
 
        A trivial optimization and a formatting fix
 
-       * lisp/subr.el (internal--compiler-macro-cXXr): Re-use `head' for `n'.
+       * lisp/subr.el (internal--compiler-macro-cXXr): Reuse `head' for `n'.
        Fix indentation and line length.
 
 2022-06-21  Tassilo Horn  <tsdh@gnu.org>
@@ -53548,7 +53548,7 @@
 
 2022-06-16  Mattias Engdegård  <mattiase@acm.org>
 
-       * src/fns.c (mapcar1): Test types in rough order of likelyhood.
+       * src/fns.c (mapcar1): Test types in rough order of likelihood.
 
 2022-06-16  Mattias Engdegård  <mattiase@acm.org>
 
@@ -53786,7 +53786,7 @@
 
        Improve drag atom computation
 
-       * src/xterm.c (xm_get_drag_window): Avoid leak if error occured
+       * src/xterm.c (xm_get_drag_window): Avoid leak if error occurred
        creating drag window.  Also use StructureNotifyMask instead of
        ButtonPressMask.
        (xm_get_drag_atom_1): Update.  Make EMACS_DRAG_ATOM a list of
@@ -54110,7 +54110,7 @@
        (Ftreesit_query_compile): New function.
        (Ftreesit_query_capture): Remove code that creates a query object and
        instead either use make_ts_query or use the give compiled query.  Free
-       the query object conditonally.
+       the query object conditionally.
        (syms_of_treesit): New symbol.
 
 2022-06-14  Yuan Fu  <casouri@gmail.com>
@@ -54121,7 +54121,7 @@
 
        Add new type treesit-compiled-query
 
-       No intergration/interaction with the new type, just adding it.
+       No integration/interaction with the new type, just adding it.
 
        * lisp/emacs-lisp/cl-preloaded.el (cl--typeof-types): Add new type.
        * src/alloc.c (cleanup_vector): Add gc for the new type.
@@ -54142,8 +54142,8 @@
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker)
        (byte-optimize-let-form, byte-optimize-letX):
        * lisp/emacs-lisp/bytecomp.el (byte-compile-unwind-protect):
-       Simplify source optimisation and codegen code that can now rely on
-       normalised let/let* and unwind-protect forms.
+       Simplify source optimization and codegen code that can now rely on
+       normalized let/let* and unwind-protect forms.
 
 2022-06-14  Mattias Engdegård  <mattiase@acm.org>
 
@@ -54161,14 +54161,14 @@
 
 2022-06-14  Mattias Engdegård  <mattiase@acm.org>
 
-       Normalise setq during macro-expansion
+       Normalize setq during macro-expansion
 
-       Early normalisation of setq during macroexpand-all allows later
+       Early normalization of setq during macroexpand-all allows later
        stages, cconv, byte-opt and codegen, to be simplified and duplicated
        checks to be eliminated.
 
        * lisp/emacs-lisp/macroexp.el (macroexp--expand-all):
-       Normalise all setq forms to a sequence of (setq VAR EXPR).
+       Normalize all setq forms to a sequence of (setq VAR EXPR).
        Emit warnings if necessary.
        * lisp/emacs-lisp/cconv.el (cconv-convert, cconv-analyze-form):
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-form-code-walker):
@@ -55015,7 +55015,7 @@
 
 2022-06-10  Po Lu  <luangruo@yahoo.com>
 
-       Fix cancelling DND upon a regular X error
+       Fix canceling DND upon a regular X error
 
        * src/xterm.c (x_connection_closed): The display isn't dead upon
        a non-IO error, so don't avoid sending messages to clean stuff
@@ -55553,7 +55553,7 @@
        Add more super and subscript characters to latin input methods
 
        * lisp/leim/quail/latin-post.el ("latin-postfix", "latin-prefix"): Add
-       mssing super and subscript characters.  (Bug#55722)
+       missing super and subscript characters.  (Bug#55722)
 
 2022-06-08  Robert Pluim  <rpluim@gmail.com>
 
@@ -55887,7 +55887,7 @@
        * src/xterm.c (x_defer_selection_requests)
        (x_release_selection_requests): New functions.
        (x_dnd_begin_drag_and_drop): Use those functions to defer
-       selections instead.  Fix error signalled when ownership of
+       selections instead.  Fix error signaled when ownership of
        XdndSelection is lost.
        (handle_one_xevent): Likewise.
 
@@ -56712,7 +56712,7 @@
        (dnd-remove-last-dragged-remote-file): Handle list values.
        (dnd-begin-file-drag): Fix file name expansion.
        (dnd-begin-drag-files): New function.
-       * lisp/select.el (xselect-convert-to-filename): Handle mutiple
+       * lisp/select.el (xselect-convert-to-filename): Handle multiple
        files
        (a vector of file names):.
 
@@ -56750,7 +56750,7 @@
        Use a space since that is clearly what was meant.
        ?\ at the end of a line (ie, ?\LF) never was well-defined and produced
        -1 most of the time, but will soon raise an error (bug#55738).
-       This doesn't matter much becaue this variable is unused.
+       This doesn't matter much because this variable is unused.
 
 2022-06-03  Po Lu  <luangruo@yahoo.com>
 
@@ -56813,7 +56813,7 @@
 
 2022-06-02  Po Lu  <luangruo@yahoo.com>
 
-       Don't call XSelectInput on a dying display when cancelling drag-and-drop
+       Don't call XSelectInput on a dying display when canceling drag-and-drop
 
        * src/xterm.c (x_dnd_free_toplevels): New argument
        `display_alive'.
@@ -56841,7 +56841,7 @@
 
        Make ?\LF generate 10, not -1 (bug#55738)
 
-       The old -1 value was an artefact of the reader implementation.
+       The old -1 value was an artifact of the reader implementation.
 
        * src/lread.c (read_escape): Remove the `stringp` argument; assume
        character literal syntax.  Never return -1.
@@ -56851,7 +56851,7 @@
 
 2022-06-02  Mattias Engdegård  <mattiase@acm.org>
 
-       * src/lread.c (skip_lazy_string): Fix uninitialised variable.
+       * src/lread.c (skip_lazy_string): Fix uninitialized variable.
 
 2022-06-02  Stefan Kangas  <stefan@marxist.se>
 
@@ -58114,7 +58114,7 @@
        This fixes bug#55684.  There, with a minibuffer-only frame at start up,
        Emacs tried to switch to this frame, whose selected window was the
        mini-window.  There is no other active window in this frame, so the
-       attempt to swith to another window failed.
+       attempt to switch to another window failed.
 
        * src/frame.c (do_switch_frame): On switching to a frame whose selected
        window is as above, before selecting the most recently used window, 
check
@@ -58617,7 +58617,7 @@
 
        * lisp/emacs-lisp/bytecomp.el (byte-compile--first-symbol-with-pos)
        (byte-compile--warning-source-offset):
-       Remove recursion for cdr-traversal of lists, and optimise (bug#55414).
+       Remove recursion for cdr-traversal of lists, and optimize (bug#55414).
 
 2022-05-26  Po Lu  <luangruo@yahoo.com>
 
@@ -59668,7 +59668,7 @@
 
        * src/haiku_support.cc (movement_locker, class EmacsWindow)
        (MouseMoved): Delete `movement_locker' and associated hack,
-       since it's superseeded by some code in haiku_read_socket.
+       since it's superseded by some code in haiku_read_socket.
        (key_map, key_chars, dpy_color_space, popup_track_message)
        (alert_popup_value, grab_view, grab_view_locker)
        (drag_and_drop_in_progress): Write comments and fix
@@ -60302,7 +60302,7 @@
 
        Also per https://github.com/joaotavora/eglot/issues/957.
 
-       Only actually and eagerly report LSP diagnotics if the user has
+       Only actually and eagerly report LSP diagnostics if the user has
        Flymake starting automatically on a timer (flymake-no-changes-timeout
        is a number).
 
@@ -60659,7 +60659,7 @@
        decorator dimensions.  Update prototypes.
 
        * src/haikufns.c (haiku_update_after_decoration_change): Ask for
-       a move frame event and don't do anything if configury is not yet
+       a move frame event and don't do anything if configurable is not yet
        complete.
 
        * src/haikuterm.c (haiku_read_socket): Adjust accordingly.
@@ -61050,7 +61050,7 @@
 
 2022-05-15  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Don't freeze Emacs on colour codes in sccs-mode
+       Don't freeze Emacs on color codes in sccs-mode
 
        * lisp/textmodes/css-mode.el (css--font-lock-keywords): Don't
        freeze Emacs on #ffffff #ffffff, and be more strict in parsing
@@ -62208,7 +62208,7 @@
 
 2022-05-11  Yoav Marco  <yoavm448@gmail.com>  (tiny change)
 
-       (sqlite-mode--column-names): Suppport nested parens
+       (sqlite-mode--column-names): Support nested parens
 
        * lisp/sqlite-mode.el (sqlite-mode--column-names): Make parsing
        more resilient (bug#55363).
@@ -62404,7 +62404,7 @@
 
 2022-05-10  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Use fields on log-edit headers (which changes `C-a' behaviour)
+       Use fields on log-edit headers (which changes `C-a' behavior)
 
        * lisp/vc/log-edit.el (log-edit-insert-message-template): Fieldify
        headers so that `C-a' takes us to the start of the string, not the
@@ -63316,7 +63316,7 @@
 
 2022-05-07  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Improve inferior-python-mode scroll behaviour
+       Improve inferior-python-mode scroll behavior
 
        * lisp/progmodes/python.el (inferior-python-mode): Use
        scroll-convervatively instead of trying to do this with a comint
@@ -63381,7 +63381,7 @@
 
 2022-05-07  Yuan Fu  <casouri@gmail.com>
 
-       Add tree-sitter intergration
+       Add tree-sitter integration
 
        * configure.ac (HAVE_TREE_SITTER, TREE_SITTER_OBJ): New variables.
        (DYNAMIC_LIB_SUFFIX): new variable, I copied code from MODULES_SUFFIX
@@ -66795,7 +66795,7 @@
 
        * doc/misc/info.texi (Search Index): Mention it.
 
-       * lisp/info.el (Info-find-node): Allow not signalling errors.
+       * lisp/info.el (Info-find-node): Allow not signaling errors.
        (Info-apropos-matches): Allow taking a regexp.
        (info-apropos): Prefix now means looking for a regexp.
 
@@ -66803,7 +66803,7 @@
 
        Fix indentation in copy-region-as-kill
 
-       * lisp/simple.el (copy-region-as-kill): Fix indendation.
+       * lisp/simple.el (copy-region-as-kill): Fix indentation.
 
 2022-04-21  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -67303,11 +67303,11 @@
 
 2022-04-18  Nacho Barrientos  <nacho.barrientos@cern.ch>  (tiny change)
 
-       Unify local variable initialisation in url-http
+       Unify local variable initialization in url-http
 
        * lisp/url/url-http.el (url-http-chunked-last-crlf-missing): Treat
        url-http-chunked-last-crlf-missing as any other buffer variable by
-       declaring and initialising it the same way as the other related
+       declaring and initializing it the same way as the other related
        ones (bug#54989).
 
 2022-04-18  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -67848,7 +67848,7 @@
        Make sure the ftcr font driver is used on Haiku when Cairo is enabled
 
        * src/haikufont.c (syms_of_haikufont): [USE_BE_CAIRO]: Make sure
-       `ftcr' superseeds `haiku'.
+       `ftcr' supersedes `haiku'.
 
 2022-04-16  Paul Eggert  <eggert@cs.ucla.edu>
 
@@ -68453,7 +68453,7 @@
 
 2022-04-15  Philip Kaludercic  <philipk@posteo.net>
 
-       Generalise buffer matching from project.el
+       Generalize buffer matching from project.el
 
        * subr.el (buffer-match): Add function to check if a buffer satisfies
        a condition.
@@ -68622,7 +68622,7 @@
        * lisp/net/ldap.el (ldap-ldapsearch-args): Change -LL to -LLL to
        suppress ldif version output.
        (ldap-search-internal): Remove skipping of version output.  Remove
-       redundand ws skipping.
+       redundant ws skipping.
 
 2022-04-14  Filipp Gunbin  <fgunbin@fastmail.fm>
 
@@ -68938,7 +68938,7 @@
        This reverts commit 78f76fe16e2737b40694f82af28d17a90a21ed7b.
 
        The commit made calls to cl-concatenate bug out, since
-       autoloading defalises doesn't work very well (bug#54901).
+       autoloading defaliases doesn't work very well (bug#54901).
 
 2022-04-12  Po Lu  <luangruo@yahoo.com>
 
@@ -69158,10 +69158,10 @@
 
 2022-04-12  Olaf Trygve Berglihn  <olafb@pvv.org>  (tiny change)
 
-       Add biblatex alias entry types for compability with bibtex
+       Add biblatex alias entry types for compatibility with bibtex
 
        * lisp/textmodes/bibtex.el (bibtex-biblatex-entry-alist): Add
-       biblatex alias entry types for compability with bibtex (bug#54877).
+       biblatex alias entry types for compatibility with bibtex (bug#54877).
 
 2022-04-12  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -69178,7 +69178,7 @@
        * src/xterm.c (x_dnd_cleanup_drag_and_drop): Always free DND
        targets even if waiting for finish.
        (x_dnd_begin_drag_and_drop): Free targets correctly when
-       signalling error and prevent activating drag-and-drop inside a
+       signaling error and prevent activating drag-and-drop inside a
        menu or popup.  (It doesn't work.)
 
 2022-04-12  Michael Albinus  <michael.albinus@gmx.de>
@@ -69301,10 +69301,10 @@
 
 2022-04-11  Mattias Engdegård  <mattiase@acm.org>
 
-       Recognise hybrid IPv6/IPv4 addresses in textsec (bug#54624)
+       Recognize hybrid IPv6/IPv4 addresses in textsec (bug#54624)
 
        * lisp/international/textsec.el (textsec--ipvx-address-p):
-         Recognise hybrid addresses like "::ffff:129.55.2.201".
+         Recognize hybrid addresses like "::ffff:129.55.2.201".
          Combine to a single regexp and translate to rx.
          Remove some regexp ambiguity (relint complaint).
        * test/lisp/international/textsec-tests.el (test-suspiction-domain):
@@ -69628,7 +69628,7 @@
        Fix DND leave events not being sent to toplevel after returning frame
 
        * src/xterm.c (x_dnd_update_state, handle_one_xevent): Make sure
-       to send leave events to the previous toplevel when cancelling to
+       to send leave events to the previous toplevel when canceling to
        return a frame.
 
 2022-04-08  Po Lu  <luangruo@yahoo.com>
@@ -70147,7 +70147,7 @@
 
        * src/xterm.c (x_dnd_begin_drag_and_drop): Verify
        x_dnd_movement_x and x_dnd_movement_y are wholenums before
-       caling posn-at-x-y.
+       calling posn-at-x-y.
 
 2022-04-07  Po Lu  <luangruo@yahoo.com>
 
@@ -70240,7 +70240,7 @@
        like server latency), then Flymake sometimes doesn't request any
        diagnostics at all.
 
-       The reason for the Flymake behaviour wasn't investigated, but that
+       The reason for the Flymake behavior wasn't investigated, but that
        wasn't a very good solution either
 
        Rather this change makes it so that when such a Flymake request comes
@@ -70735,7 +70735,7 @@
 
        Reduce GC mark-phase recursion by using explicit stack (bug#54698)
 
-       An explict stack of objects to be traversed for marking replaces
+       An explicit stack of objects to be traversed for marking replaces
        recursion for most common object types: conses, vectors, records, hash
        tables, symbols, functions etc.  Recursion is still used for other
        types but those are less common and thus not as likely to cause a
@@ -70859,7 +70859,7 @@
        Rework eglot's mode-line
 
        Mimic flymake by replacing the old menus of the mode-line with
-       "context menus".  List all usefull commands under the main menu
+       "context menus".  List all useful commands under the main menu
        (eglot-menu-map), and commands related to LSP debugging under the
        project menu (eglot-debug-map).
 
@@ -70903,7 +70903,7 @@
 
        Since <, <=, > and >= have their own byte-ops, the corresponding
        functions are mostly used as arguments to higher-order functions.
-       This optimisation is particularly beneficial for sorting, where the
+       This optimization is particularly beneficial for sorting, where the
        comparison function is time-critical.
 
        * src/data.c (Flss, Fgtr, Fleq, Fgeq):
@@ -70926,7 +70926,7 @@
        Faster `string-lessp` for unibyte arguments
 
        Since this function is commonly used as a sorting predicate
-       where it is time-critical, this is a useful optimisation.
+       where it is time-critical, this is a useful optimization.
 
        * src/fns.c (Fstring_lessp): Add fast path for the common case
        when both arguments are unibyte.
@@ -71030,7 +71030,7 @@
          echo "\\"
 
        * lisp/eshell/esh-util.el (eshell-find-delimiter): Correct docstring
-       and treat '\' as an escapeable character when using backslash escapes.
+       and treat '\' as an escapable character when using backslash escapes.
 
        * test/lisp/eshell/eshell-tests.el
        (eshell-test/escape-special-quoted): Adapt test.
@@ -71158,7 +71158,7 @@
        Fix incorrect usage of XM_DRAG_SIDE_EFFECT
 
        * src/xterm.c (xm_send_top_level_leave_message)
-       (handle_one_xevent): Pass corret alt side effects and flags to
+       (handle_one_xevent): Pass correct alt side effects and flags to
        XM_DRAG_SIDE_EFFECT.
 
 2022-04-02  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -71441,10 +71441,10 @@
 
        * etc/themes/modus-operandi-theme.el:
        * etc/themes/modus-vivendi-theme.el: Ensure that the theme is reified
-       as expected both at compiletime and runtime.
+       as expected both at compile time and runtime.
 
        * etc/themes/modus-themes.el (require): Require 'cl-lib' and 'subr-x'
-       at compiletime.
+       at compile time.
        (seq): Require the 'seq' library.
        (modus-themes-completion-standard-first-match)
        (modus-themes-completion-standard-selected)
@@ -71683,7 +71683,7 @@
 
        * src/pdumper.c (dump_get_max_page_size): Rename from 
'dump_get_page_size'.
 
-       * src/pdumper.c: Remove getpagesize.h dependecy.
+       * src/pdumper.c: Remove getpagesize.h dependency.
 
 2022-03-30  Michael Albinus  <michael.albinus@gmx.de>
 
@@ -72118,7 +72118,7 @@
 
        Make sure that the value added to the `read_objects_completed` set is
        the one we actually return; previously this wasn't the case for conses
-       because of an optimisation (bug#54501).
+       because of an optimization (bug#54501).
 
        Also add a check for vacuous self-references such as #1=#1# instead of
        returning a nonsense value from thin air.
@@ -72848,7 +72848,7 @@
        by RFC 5322.
 
        When eudc-inline-expansion-format remains set to a list as previously,
-       the old behaviour is fully retained.
+       the old behavior is fully retained.
 
 2022-03-22  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -73369,7 +73369,7 @@
 
 2022-03-19  Po Lu  <luangruo@yahoo.com>
 
-       Improve behaviour of drag-n-drop during window manager operations
+       Improve behavior of drag-n-drop during window manager operations
 
        * src/xterm.c (x_dnd_begin_drag_and_drop): Select for some
        events on the root window.
@@ -74070,7 +74070,7 @@
        generation of random bignums without using Frem etc.
        * src/fns.c (get_random_fixnum): New function.
        (Frandom): Use it, and get_random_bignum.
-       Be consistent about signalling nonpositive integer arguments;
+       Be consistent about signaling nonpositive integer arguments;
        since zero is invalid, Qnatnump is not quite right here.
        * src/sysdep.c (get_random_ulong): New function.
 
@@ -74684,7 +74684,7 @@
        This results in better performance, and bytecode recursion is no
        longer limited by the size of the C stack.  The bytecode stack is
        currently of fixed size but overflow is handled gracefully by
-       signalling a Lisp error instead of the hard crash that we get now.
+       signaling a Lisp error instead of the hard crash that we get now.
 
        In addition, GC marking of the stack is now faster and more precise.
        Full precision could be attained if desired.
@@ -74911,7 +74911,7 @@
        Return the same file from locate-file in nativecomp and non
 
        * lisp/files.el (locate-file): Return the .elc file (if it exists)
-       in nativecomp, too, to mimic the behaviour from non-nativecomp
+       in nativecomp, too, to mimic the behavior from non-nativecomp
        builds (bug#51308).
 
 2022-03-12  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -74931,7 +74931,7 @@
 
 2022-03-12  Alexander Adolf  <alexander.adolf@condition-alpha.com>
 
-       Facilitate Customisation of Message-Mode Header Completion Behaviour
+       Facilitate Customization of Message-Mode Header Completion Behavior
 
        * lisp/gnus/message.el (message-email-recipient-header-regexp):
        New user option.
@@ -74966,7 +74966,7 @@
 
        * src/bytecode.c (FETCH2):
        Use `|` instead of `+` to combine the bytes forming a 16-bit immediate
-       argument so that GCC (prior to version 12) recognises the idiom and
+       argument so that GCC (prior to version 12) recognizes the idiom and
        generates a 16-bit load.  This applies for little-endian machines with
        cheap unaligned accesses such as x86[-64], arm64 and power64le.
 
@@ -74974,7 +74974,7 @@
        kinds of Lisp code, as 16-bit immediates are used by all jump
        instructions.
 
-       Clang performs this optimisation for both `+` and `|` from version 10.
+       Clang performs this optimization for both `+` and `|` from version 10.
 
 2022-03-12  Mattias Engdegård  <mattiase@acm.org>
 
@@ -75284,7 +75284,7 @@
        Support remote home directories via connection property
 
        * doc/misc/tramp.texi (Home directories): New section.
-       (Top, Usage): Add it to the menue.
+       (Top, Usage): Add it to the menu.
        (Predefined connection information): Mention "~".
        (Multi-hops, File name syntax): Fix typos.
 
@@ -75704,7 +75704,7 @@
        Merge from origin/emacs-28
 
        73f28fbde8 Add a comment for previous browse-url-of-dired-file change
-       9b74e84857 Restore documented Emacs 27.2 behaviour of browse-url-of-d...
+       9b74e84857 Restore documented Emacs 27.2 behavior of browse-url-of-d...
        cd77fd3b85 Update to Org 9.5.2-24-g668205
 
 2022-03-07  Manuel Giraud  <manuel@ledu-giraud.fr>
@@ -75867,7 +75867,7 @@
 
 2022-03-06  Mattias Engdegård  <mattiase@acm.org>
 
-       Don't accept whitespace or hex floats in rgbi: colour specs
+       Don't accept whitespace or hex floats in rgbi: color specs
 
        `color-values-from-color-spec` (new in Emacs 28) erroneously accepted
        leading whitespace and hex floats in rgbi: components.
@@ -78381,7 +78381,7 @@
 
        Fix SIGFPE on some fonts when calculating their average width on Haiku
 
-       * src/haiku_font_support.cc (estimate_font_ascii): Avoid divison
+       * src/haiku_font_support.cc (estimate_font_ascii): Avoid division
        by zero.
 
 2022-02-16  Po Lu  <luangruo@yahoo.com>
@@ -78466,7 +78466,7 @@
 
        * src/character.c (count_size_as_multibyte): Move the overflow test
        outside the loop, which makes it much faster.  Standard compilers
-       will even vectorise it if asked to (-O2 in Clang, -O3 in GCC).
+       will even vectorize it if asked to (-O2 in Clang, -O3 in GCC).
 
 2022-02-16  Mattias Engdegård  <mattiase@acm.org>
 
@@ -78694,7 +78694,7 @@
        (vc-clone): Declare function for package-unpack.
        (package-unpack): Handle source packages.
        (package-generate-description-file): Handle source packages by
-       ommiting a version number.
+       omitting a version number.
        (package-install-from-archive): Check if a package is a source
        package.
        (package-fetch): Add new command
@@ -78791,7 +78791,7 @@
 
 2022-02-14  Po Lu  <luangruo@yahoo.com>
 
-       * etc/TODO: Update some entires related to macOS and NS.
+       * etc/TODO: Update some entries related to macOS and NS.
 
        Xwidgets have worked on NS for a long time, "smooth scrolling"
        is now available as `pixel-scroll-precision-mode' for all GUI
@@ -78821,7 +78821,7 @@
 
 2022-02-13  Po Lu  <luangruo@yahoo.com>
 
-       Improve efficency of handling DeviceChanged events
+       Improve efficiency of handling DeviceChanged events
 
        * src/xterm.c (handle_one_xevent): Just update the device that
        was changed on DeviceChanged and only do hierarchy recalculation
@@ -78974,7 +78974,7 @@
 
 2022-02-12  Po Lu  <luangruo@yahoo.com>
 
-       Stop quering for Xinerama inside x_get_monitor_attributes
+       Stop querying for Xinerama inside x_get_monitor_attributes
 
        * src/xfns.c (x_get_monitor_attributes): Remove Xinerama check
        and use xinerama_supported_p instead.
@@ -79096,7 +79096,7 @@
        specpdl refs has been converted.
 
        We only do this on 64-bit platforms, since those tend to have modern
-       ABIs where small structs are optimised as scalars.  In other words,
+       ABIs where small structs are optimized as scalars.  In other words,
        this change should not affect the compiled code.
 
        * src/lisp.h (specpdl_ref): Now a struct on 64-bit platforms.
@@ -79332,7 +79332,7 @@
 
 2022-02-11  Mattias Engdegård  <mattiase@acm.org>
 
-       Modernise byte-compilation chapters in manual
+       Modernize byte-compilation chapters in manual
 
        * doc/lispref/compile.texi (Speed of Byte-Code): More representative
        numbers for byte code; the difference is much greater today.
@@ -79484,7 +79484,7 @@
        Restore command-line--load-script messaging
 
        * lisp/startup.el (command-line--load-script): Restore previous
-       non-messaging behaviour.
+       non-messaging behavior.
 
 2022-02-10  Michael Albinus  <michael.albinus@gmx.de>
 
@@ -79681,14 +79681,14 @@
 
 2022-02-09  Po Lu  <luangruo@yahoo.com>
 
-       Explictly specify whether or not to respect alpha-background on Cairo
+       Explicitly specify whether or not to respect alpha-background on Cairo
 
        * src/ftcrfont.c (ftcrfont_draw): Don't respect
        `alpha-background' if drawing cursor.  (bug#53890)
        * src/xterm.c (x_set_cr_source_with_gc_foreground):
        (x_set_cr_source_with_gc_background): New parameters
        `respect_alpha_background'.  All callers changed.
-       * src/xterm.h: Update protoypes.
+       * src/xterm.h: Update prototypes.
 
 2022-02-09  Tassilo Horn  <tsdh@gnu.org>
 
@@ -79945,7 +79945,7 @@
 
        * src/widget.c (update_wm_hints): Accept frame separately from
        the shell widget.
-       (widget_update_wm_size_hints): Require WM shell to be explictly
+       (widget_update_wm_size_hints): Require WM shell to be explicitly
        specified.
        (EmacsFrameRealize):
        (EmacsFrameResize): Update callers to `update_wm_hints'.
@@ -80411,7 +80411,7 @@
        Add a :distant-foreground to the lazy-highlight face
 
        * lisp/isearch.el (lazy-highlight): Add a :distant-foreground
-       colour so that the text is always legible (bug#16969).
+       color so that the text is always legible (bug#16969).
 
 2022-02-05  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -80841,7 +80841,7 @@
        error will occur in x_composite_image as libXpm will load
        pixmaps of depth 16 instead of depth 32.
 
-       * src/image.c (x_create_x_image_and_pixmap): Explictly specify
+       * src/image.c (x_create_x_image_and_pixmap): Explicitly specify
        display depth.
        (x_create_xrender_picture):
        (xpm_load):
@@ -81097,7 +81097,7 @@
        of not being in dumping or bootstrap, since it is no longer needed.  
Test that
        'debug-early's symbol-function is bound.  Ensure there is enough 
working space
        in specpdl and eval_depth.
-       (syms_of_eval): New DEFSYM for Qdebug_early.  Initialise Vdebugger to
+       (syms_of_eval): New DEFSYM for Qdebug_early.  Initialize Vdebugger to
        Qdebug_early rather than Qnil.
 
 2022-02-02  Juri Linkov  <juri@linkov.net>
@@ -81169,7 +81169,7 @@
 
 2022-02-02  Po Lu  <luangruo@yahoo.com>
 
-       Make behaviour of `mouse-autoselect-window' consistent with X on NS
+       Make behavior of `mouse-autoselect-window' consistent with X on NS
 
        * src/nsterm.m ([EmacsView mouseMoved:]): Ignore if
        `selected_window' is a minibuffer window.
@@ -81185,7 +81185,7 @@
 
 2022-02-01  Po Lu  <luangruo@yahoo.com>
 
-       Improve behaviour of `mouse-autoselect-window' on Haiku
+       Improve behavior of `mouse-autoselect-window' on Haiku
 
        * src/haikuterm.c (haiku_read_socket): Don't select windows if
        the selected window is a minibuffer window or a popup is
@@ -81445,7 +81445,7 @@
 
        We used to store in `load-history` when an autoload is redefined as
        a non-autoload and in the `autoload` symbol property we used to store
-       the autoload data that used to be used before it got overriden.
+       the autoload data that used to be used before it got overridden.
 
        Instead, store the history of the function definition of
        a symbol in its `function-history` symbol property.
@@ -81839,7 +81839,7 @@
 
 2022-01-29  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Modernise the security section in the efaq a bit
+       Modernize the security section in the efaq a bit
 
        * doc/misc/efaq.texi (Security risks with Emacs): Remove the X
        bit, and add a bit about browsing the web (bug#24489).
@@ -82477,7 +82477,7 @@
        Minor `concat` tweaks
 
        * src/fns.c (concat): Do things in the right order for speed.
-       (concat_strings): Initialise variable.
+       (concat_strings): Initialize variable.
 
 2022-01-26  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -82648,7 +82648,7 @@
        (Fappend, Fvconcat): Adapt to changed signature of concat.
        (Fcopy_sequence): Faster implementation for lists, strings, and vectors.
        (concat_strings): New.
-       (concat): Strip code for string target, simplify, optimise.
+       (concat): Strip code for string target, simplify, optimize.
        (Fcopy_alist): Use Fcopy_sequence.
 
 2022-01-25  Lars Ingebrigtsen  <larsi@gnus.org>
@@ -83912,7 +83912,7 @@
        Make diff--iterate-hunks more resilient
 
        * lisp/vc/diff-mode.el (diff--iterate-hunks): Ignore malformed
-       hunks instead of signalling errors (bug#53343).
+       hunks instead of signaling errors (bug#53343).
 
 2022-01-21  Shuguang Sun  <shuguang79@qq.com>
 
@@ -83936,7 +83936,7 @@
        than before, for example when a subcommand is concatenated in an
        argument.
 
-       * lisp/eshell/esh-cmd.el (eshell--find-subcommands): New fuction.
+       * lisp/eshell/esh-cmd.el (eshell--find-subcommands): New function.
        (eshell--invoke-command-directly): Use 'eshell-find-subcommands'.
 
        * test/lisp/eshell/eshell-tests.el
@@ -84662,7 +84662,7 @@
 
        Fix event timestamp generation on Haiku
 
-       * src/haikuterm.c (haiku_read_socket): Use miliseconds for event
+       * src/haikuterm.c (haiku_read_socket): Use milliseconds for event
        time.
 
 2022-01-18  Stefan Monnier  <monnier@iro.umontreal.ca>
@@ -84849,7 +84849,7 @@
 
        This fixes several issues: tooltips having no right internal
        border, reusing tooltips occasionally freezing Emacs, and
-       inconsistent behaviour when compared to X.
+       inconsistent behavior when compared to X.
 
        * src/haiku_support.cc (BWindow_resize): Revert a recent change.
        (BView_move_frame):
@@ -85295,7 +85295,7 @@
 
        * src/haiku_support.c (be_popup_file_dialog): Reduce idle
        processor load by increasing timeout.  The timeout is still too
-       low to be noticable by the user.
+       low to be noticeable by the user.
 
 2022-01-16  Po Lu  <luangruo@yahoo.com>
 
@@ -85419,7 +85419,7 @@
        mechanism.
        (byte-compile-function-warn): Replace byte-compile-last-position by a
        symbol-with-pos-pos call.
-       (compile-defun): Use local variable start-read-position to fulfil 
purpose of
+       (compile-defun): Use local variable start-read-position to fulfill 
purpose of
        old byte-compile-read-position.  Push the just read FORM onto
        byte-compile-form-stack.
 
@@ -85640,7 +85640,7 @@
 
        No longer strip positions from symbols before each use of a form, 
instead
        relying on the low level C routines to do the right thing.  Instead 
strip them
-       from miscellaneous places where this is needed.  Stip them alson in
+       from miscellaneous places where this is needed.  Strip them also in
        `function-put'.
 
        Push forms onto byte-compile-form-stack and pop them "by hand" rather 
than by
@@ -85816,7 +85816,7 @@
 
        * lisp/battery.el (battery-status-function): In Termux, neither
        /sys/ or /proc/ are readable on phones that are not rooted. This
-       patch makes Emacs verify if they are readable before it attemps
+       patch makes Emacs verify if they are readable before it attempts
        reading them (bug#53026).
 
 2022-01-14  Robert Pluim  <rpluim@gmail.com>
@@ -85875,7 +85875,7 @@
 
        * lisp/progmodes/python.el (python-shell-send-string-no-output): Don't
        let-bind comint-preoutput-filter-functions globally for all comint
-       processes.  Modify the behaviour of only the current python
+       processes.  Modify the behavior of only the current python
        process (bug#53219).
 
 2022-01-14  Robert Pluim  <rpluim@gmail.com>
@@ -85904,7 +85904,7 @@
        Merge from origin/emacs-28
 
        34ca4ff9a5 Fix Edebug specification for inline functions (Bug#53068).
-       3c06c37a8b Remove mention of removed `gnus-treat-play-sounds' variabl...
+       3c06c37a8b Remove mention of removed `gnus-treat-play-sounds' 
variable...
 
 2022-01-13  Po Lu  <luangruo@yahoo.com>
 
@@ -86777,7 +86777,7 @@
        This was found during the investigation surrounding bug#53136,
        but is not directly related.
 
-       * src/filelock.c (lock_if_free): Explictly test err against -1
+       * src/filelock.c (lock_if_free): Explicitly test err against -1
        or -2, and reverse sign of system errors on Haiku.  (No Haiku
        error occupies -1 or -2.)
 
@@ -87231,7 +87231,7 @@
 
 2022-01-07  Po Lu  <luangruo@yahoo.com>
 
-       Disable new input method behaviour by default on X
+       Disable new input method behavior by default on X
 
        * src/xfns.c (supported_xim_styles): Default to STYLE_NONE.
 
@@ -87818,7 +87818,7 @@
        here.
 
        * src/haikufns.c (haiku_visualize_frame):
-       (haiku_unvisualize_frame): Sychronize after visibility changes.
+       (haiku_unvisualize_frame): Synchronize after visibility changes.
 
 2022-01-03  Po Lu  <luangruo@yahoo.com>
 
@@ -88558,9 +88558,9 @@
        (emit_ctxt_code): Export the global 
F_SYMBOLS_WITH_POS_ENABLED_RELOC_SYM.
        (define_lisp_symbol_with_position, define_GET_SYMBOL_WITH_POSITION): New
        functions.
-       (Fcomp__init_ctxt): Initialise comp.bool_ptr_type, call the two new
+       (Fcomp__init_ctxt): Initialize comp.bool_ptr_type, call the two new
        define_.... functions.
-       (load_comp_unit): Initialise **f_symbols_with_pos_enabled_reloc.
+       (load_comp_unit): Initialize **f_symbols_with_pos_enabled_reloc.
 
        * src/fns.c (Fput): Strip positions from symbols in PROPNAME and VALUE.
 
@@ -89045,7 +89045,7 @@
 
 2021-12-27  Michael Albinus  <michael.albinus@gmx.de>
 
-       The temprary "session" collection might not exist in Secret Service
+       The temporary "session" collection might not exist in Secret Service
 
        * doc/misc/auth.texi (Secret Service API):
        * test/lisp/net/secrets-tests.el 
(secrets--test-delete-all-session-items)
@@ -89600,7 +89600,7 @@
 
        Changes:
        - structure the result of mm-dissect-buffer of application/pkcs7-mime
-         like a multipart mail so there is no loosing of information of
+         like a multipart mail so there is no losing of information of
          verification and decryption results which can now be displayed by
          gnus-mime-display-security
 
@@ -89616,7 +89616,7 @@
          to print "Encrypted" or "Signed" accordingly in the security button
 
        - adjust mm-possibly-verify-or-decrypt to check for smime-type to ask
-         wether to verify or decrypt the part and not to always ask to decrypt
+         whether to verify or decrypt the part and not to always ask to decrypt
 
        - adjust mm-view-pkcs7-decrypt and verify to call mm-sec-status so
          success information can be displayed by gnus-mime-display-security
@@ -89992,7 +89992,7 @@
        * src/xfns.c (Fx_set_mouse_absolute_pixel_position):
        * src/xterm.c (frame_set_mouse_pixel_position): Replace
        calls to XWarpPointer with calls to XIWarpPointer with
-       the client pointer explictly specified.  This avoids the
+       the client pointer explicitly specified.  This avoids the
        odd situation where the client pointer of the root window
        is not the client pointer of the frame.
 
@@ -90655,7 +90655,7 @@
 
        Remove incorrect byte-hunk-handler for `eval`
 
-       This optimisation is of very limited utility and miscompiles top-level
+       This optimization is of very limited utility and miscompiles top-level
        code having the form (eval 'CODE t) by replacing it with CODE which
        will then, as things currently stand, be evaluated with dynamic binding.
 
@@ -92005,7 +92005,7 @@
        be860c1385 Fix manual entry of 'quit-restore-window' (Bug#52328)
        35a96139df Clarify a comment in xdisp.c
        6ba2f028cf Revert "Grep alias `all' shall not match parent directory"
-       eb9e33e238 ; * etc/NEWS: Non-nil repeat-keep-prefix is not the defaul...
+       eb9e33e238 ; * etc/NEWS: Non-nil repeat-keep-prefix is not the 
default...
        538fc1d0e0 Fix mode-line display in Calendar mode
 
        # Conflicts:
@@ -93530,14 +93530,14 @@
        Remove separators at the beginning and end of the context menu
 
        * lisp/mouse.el (context-menu-map): Remove beginning/end
-       seperators (bug#52237).
+       separators (bug#52237).
 
 2021-12-03  Lars Ingebrigtsen  <larsi@gnus.org>
 
        Improve how dired-mark-sexp interprets file sizes in non-C locales
 
        * lisp/dired-x.el (dired-x--string-to-number): Try to understand
-       localised numbers (with "." separators or the like) (bug#23373).
+       localized numbers (with "." separators or the like) (bug#23373).
 
 2021-12-03  Stefan Kangas  <stefan@marxist.se>
 
@@ -93572,7 +93572,7 @@
 
 2021-12-03  Stefan Kangas  <stefan@marxist.se>
 
-       image-mode: Advertize viewing as text less eagerly
+       image-mode: Advertise viewing as text less eagerly
 
        * lisp/image-mode.el (image-text-based-formats): New defcustom.
        (image-mode--setup-mode): Don't show message to show image as text
@@ -93716,7 +93716,7 @@
        2be090d5d3 ; * ChangeLog.3: Minor fixes.
        9963b11bf7 ; * admin/authors.el (authors-aliases): Further updates.
        50b40e1d4f ; * lisp/org/ob-julia.el: Fix Author header for authors.el.
-       84166ea2e6 CC Mode: Recognise "struct foo {" as introducing a type de...
+       84166ea2e6 CC Mode: Recognize "struct foo {" as introducing a type de...
 
 2021-12-02  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -93943,7 +93943,7 @@
 
        * lisp/pixel-scroll.el (pixel-scroll-precision-scroll-down)
        (pixel-scroll-precision-scroll-up): Take scroll margin into
-       accout.
+       account.
 
 2021-12-01  Po Lu  <luangruo@yahoo.com>
 
@@ -94360,7 +94360,7 @@
 
 2021-11-30  Andrea Corallo  <akrl@sdf.org>
 
-       Improve native compiler startup circular dependecy prevention mechanism
+       Improve native compiler startup circular dependency prevention mechanism
 
        * src/comp.c (maybe_defer_native_compilation): Update to accumulate
        delayed objects in `comp--delayed-sources'.
@@ -94382,7 +94382,7 @@
 
 2021-11-30  Mattias Engdegård  <mattiase@acm.org>
 
-       Generalise CPS-conversion let optimisation
+       Generalize CPS-conversion let optimization
 
        * lisp/emacs-lisp/generator.el (cps--transform-1):
        Eliminate a temporary for the last of any `let` form, not just for
@@ -94452,7 +94452,7 @@
 
        30553d889d Merge branch 'emacs-28' of git.savannah.gnu.org:/srv/git/e...
        ecf3bf66ba Remove problematic characters from modus-themes.org (bug#5...
-       de9d27f679 Avoid undefined behaviour when copying part of structure
+       de9d27f679 Avoid undefined behavior when copying part of structure
 
        # Conflicts:
        #       doc/misc/modus-themes.org
@@ -94925,7 +94925,7 @@
 
 2021-11-29  Andreas Schwab  <schwab@linux-m68k.org>
 
-       Avoid undefined behaviour when copying part of structure
+       Avoid undefined behavior when copying part of structure
 
        * src/dispnew.c (copy_row_except_pointers): Don't use address of
        subobject as starting point.
@@ -97333,7 +97333,7 @@
 
        * lisp/emacs-lisp/ert.el (ert-batch-backtrace-line-length): Fix
        docstring.
-       (ert-run-tests-batch): Remove redundand let-binding.
+       (ert-run-tests-batch): Remove redundant let-binding.
        (ert-run-tests-interactively): Fix interactive spec.
 
 2021-11-18  Mattias Engdegård  <mattiase@acm.org>
@@ -98175,7 +98175,7 @@
        Merge from origin/emacs-28
 
        5dbad52 gnus-summary-line-format doc string clarification
-       d4536ff Fix follow-scroll-down in a small buffer which starts slightl...
+       d4536ff Fix follow-scroll-down in a small buffer which starts 
slightly...
 
 2021-11-14  Eli Zaretskii  <eliz@gnu.org>
 
@@ -98335,7 +98335,7 @@
 
 2021-11-13  Michael Albinus  <michael.albinus@gmx.de>
 
-       Revert accidential commit in icomplete.el
+       Revert accidental commit in icomplete.el
 
 2021-11-13  Michael Albinus  <michael.albinus@gmx.de>
 
@@ -98401,7 +98401,7 @@
 
        Where c-record-found-types gets "bound" to itself, we postpone the 
calling of
        c-fontify-new-type on possible new found types until these are 
confirmed by
-       the return from the function tentatively finding these types, for 
exmaple
+       the return from the function tentatively finding these types, for 
example
        c-forward-<>-arglist.  We check this "binding" by testing the value of
        c-record-found-types.
 
@@ -100934,7 +100934,7 @@
        5e9b4e70ab Fix dbus-test04-register-method on CentOS (Bug#51369)
        d96de23510 * lisp/transient.el: Update to package version v0.3.7-11-g...
        7343b0d0e4 ; * etc/NEWS: Native compilation is more picky about missi...
-       0d6b2b0b9d ; * etc/PROBLEMS: Move entry about LLVM plugin to the righ...
+       0d6b2b0b9d ; * etc/PROBLEMS: Move entry about LLVM plugin to the 
right...
 
        # Conflicts:
        #       etc/NEWS
@@ -100991,7 +100991,7 @@
        (ns_glyph_metrics): Stop escaping names.
 
        (ns_spec_to_descriptor): Fix font descriptor creation for symbolic
-       font spec entires.
+       font spec entries.
        (ns_descriptor_to_entity): Create entries with the correct symbolic
        styles.
 
@@ -101763,11 +101763,11 @@
 
 2021-11-02  Mattias Engdegård  <mattiase@acm.org>
 
-       Optimise (cond) => nil at source level
+       Optimize (cond) => nil at source level
 
        * lisp/emacs-lisp/byte-opt.el (byte-optimize-cond):
-       Optimise clause-free `cond`, which can arise from earlier
-       transformations.  This enables further optimisations.
+       Optimize clause-free `cond`, which can arise from earlier
+       transformations.  This enables further optimizations.
        * test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-tests--test-cases):
        Add test cases.
 
@@ -102644,10 +102644,10 @@
 
 2021-10-26  Stefan Kangas  <stefan@marxist.se>
 
-       image-dired: Improve mouse behaviour
+       image-dired: Improve mouse behavior
 
        * lisp/image-dired.el (image-dired-thumbnail-mode-map): Improve mouse
-       behaviour: ignore dragging, as it currently doesn't do anything
+       behavior: ignore dragging, as it currently doesn't do anything
        useful, and make all clicks just select the thumbnail.
        (image-dired-mouse-display-image)
        (image-dired-mouse-select-thumbnail): Move point to closest image
@@ -102758,7 +102758,7 @@
        strings. The code originally set that charset for any server with
        literal+ capability, borking all searches on an Exchange server. This
        code only sets utf-8 for multibyte search strings in particular, which
-       would be borken for Exchange anyway.
+       would be broken for Exchange anyway.
 
        * lisp/gnus/gnus-search.el (gnus-search-imap-search-command): Ensure
        we're only doing the literal+ dance for multibyte strings (multibyte
@@ -102933,7 +102933,7 @@
 
 2021-10-24  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Display a message if HMTL rendering takes a long time
+       Display a message if HTML rendering takes a long time
 
        * lisp/net/eww.el (eww-display-html): Display a message if HTML
        rendering takes a long time (bug#19776).
@@ -102956,7 +102956,7 @@
        This aims to fix the scenario where on jit-lock's first scan of a type, 
it is
        not recognized as such, and only later does this happen.  The 
fontification of
        such found types is now done by background scanning in short time slices
-       immediately after initialising the mode.
+       immediately after initializing the mode.
 
        * lisp/progmodes/cc-engine.el (c-add-type-1): New function.
        (c-add-type): Extract c-add-type-1 from it, and reformulate the 
mechanism for
@@ -103172,7 +103172,7 @@
        Make dired-x-guess-file-name-at-point obsolete
 
        * lisp/dired-x.el (dired-x-guess-file-name-at-point): Make
-       obsolete in favour of 'thing-at-point'.
+       obsolete in favor of 'thing-at-point'.
        (dired-x-read-filename-at-point): Use 'thing-at-point' instead of
        above obsolete function.
 
@@ -103209,7 +103209,7 @@
        * lisp/image-dired.el (exif): Require.
        (image-dired-cmd-read-exif-data-program)
        (image-dired-cmd-read-exif-data-options)
-       (image-dired-get-exif-data): Make obsolete in favour of using
+       (image-dired-get-exif-data): Make obsolete in favor of using
        exif.el.  This removes a dependency on external exiftool for some
        operations.
        (image-dired-get-exif-file-name)
@@ -103254,7 +103254,7 @@
        This aims to fix the scenario where on jit-lock's first scan of a type, 
it is
        not recognized as such, and only later does this happen.  The 
fontification of
        such found types is now done by background scanning in short time slices
-       immediately after initialising the mode.
+       immediately after initializing the mode.
 
        * lisp/progmodes/cc-engine.el (c-add-type-1): New function.
        (c-add-type): Extract c-add-type-1 from it, and reformulate the 
mechanism for
@@ -104586,7 +104586,7 @@
 
        Merge from origin/emacs-28
 
-       47e09d1855 Copy parent face attributes to tab-line-tab-current instea...
+       47e09d1855 Copy parent face attributes to tab-line-tab-current 
instead...
        d96f8b22c0 Another fix for 'ibuffer-shrink-to-fit' (Bug#7218, Bug#51029)
 
 2021-10-12  Glenn Morris  <rgm@gnu.org>
@@ -104918,7 +104918,7 @@
        315fe20086 ; * src/Makefile.in (../native-lisp): Add comment.
        47cbd103f5 * lisp/bindings.el (mode-line-position): Improve tooltip.
        35a752863a * lisp/progmodes/xref.el: Bump the version.
-       bbcd8cc1a9 Slight simplificaiton
+       bbcd8cc1a9 Slight simplification
        e139dd1b1e Fix doc strings of 2 categories
        59782839cb (xref--collect-matches-1): Remove some intermediate alloca...
        1c7d056f4d ; Fix two typos where em dash was written as en dash
@@ -105585,7 +105585,7 @@
        (term-ansi-face-already-done): Make obsolete
        (term--maybe-brighten-color): Remove
        (term--color-as-hex): New function
-       (term-handle-colors-array): Make obsolete in favour of the new
+       (term-handle-colors-array): Make obsolete in favor of the new
        function 'term--handle-colors-list'.
        (term--handle-colors-list): New function, that can also handle ANSI
        codes 38 and 48.
@@ -106426,7 +106426,7 @@
        Use project-files to know which directory watchers to skip
 
        The directory-finding logic is probably a bit slower than using
-       eglot--directories-recursively, but since it honours `.gitignores` and
+       eglot--directories-recursively, but since it honors `.gitignores` and
        ignores more directories it's much faster overall.  And guaranteed to
        create less watchers.
 
@@ -106438,7 +106438,7 @@
 
 2021-05-26  João Távora  <joaotavora@gmail.com>
 
-       Hard code an exception to "node_modules" directores
+       Hard code an exception to "node_modules" directories
 
        * eglot.el (eglot--directories-recursively): Fix.
 
@@ -106833,7 +106833,7 @@
        tremendeously slow down the process.  But this is only a suspicion.
 
        This commit tries some simple optimizations: if a directory is known
-       to be watch-worthy becasue one of its files matched a single glob, no
+       to be watch-worthy because one of its files matched a single glob, no
        more files under that directory are tried.  This should help somewhat.
 
        Also fixed a bug in 'eglot--files-recursively', though I suspect that
@@ -107246,7 +107246,7 @@
        Simplify dir-watching strategy of w/didchangewatchedfiles
 
        Instead of massaging the globPattern to match directories instead of
-       files, which is fragile, gather the list of directoris to watch by
+       files, which is fragile, gather the list of directories to watch by
        matching the globPattern against every file recursively (except hidden
        files and dirs).
 
@@ -107783,7 +107783,7 @@
        Only makes two changes: a deletion of the "// " and a replacement of a
        newline with a space character.  The second change fooled Eglot's fix
        for https://github.com/joaotavora/eglot/issues/259, by making a change 
similar to the one it is made to detect
-       and correct.  That fix should taget things that happen on the same
+       and correct.  That fix should target things that happen on the same
        line, this not being one of those things.
 
        * eglot.el (eglot--after-change): Only apply fix to 
https://github.com/joaotavora/eglot/issues/259 if
@@ -107897,7 +107897,7 @@
        * src/pgtkselect.c:
        * src/pgtkselect.h:
        * src/pgtkterm.c:
-       * src/pgtkterm.h: Update copyright dates - No Funtional Changes
+       * src/pgtkterm.h: Update copyright dates - No Functional Changes
 
 2020-11-23  Yuuki Harano  <masm+github@masm11.me>
 
@@ -108296,7 +108296,7 @@
 
        minimize gtkutil.c differences.
 
-       * src/pgtkterm.h: remove compiletime ifdefs
+       * src/pgtkterm.h: remove compile time ifdefs
 
        * src/gtkutil.h: block out unused decl
 
@@ -108345,7 +108345,7 @@
 
        * src/gtkutil.c (xg_create_frame_widgets):
 
-       hacky GTK offsets taht will need better calculations
+       hacky GTK offsets that will need better calculations
 
        Get parent frame's editor widget allocation for the offset
 
@@ -108511,7 +108511,7 @@
 
 2020-11-21  Yuuki Harano  <masm+github@masm11.me>
 
-       Make multipdisplay work by limiting selection while enabed
+       Make multipdisplay work by limiting selection while enabled
 
        * src/pgtkterm.c (pgtk_mouse_position):
 
@@ -108528,12 +108528,12 @@
 
 2020-11-21  Yuuki Harano  <masm+github@masm11.me>
 
-       Improve drawing efficency by refactoring code
+       Improve drawing efficiency by refactoring code
 
                * ../src/pgtkterm.c (fill_background, fill_background_by_face)
                (x_draw_glyph_string_background, x_draw_glyph_string_bg_rect)
                (x_draw_image_glyph_string, x_draw_stretch_glyph_string)
-               (pgtk_clear_under_internal_border): Refator duplcate code
+               (pgtk_clear_under_internal_border): Refator duplicate code
 
        更に効率化。
 
@@ -108849,7 +108849,7 @@
 
 2020-11-21  Yuuki Harano  <masm+github@masm11.me>
 
-       Simplify compilaiton condtion
+       Simplify compilation condition
 
                * ../src/menu.c (single_menu_item):
 
@@ -109221,7 +109221,7 @@
        Uses Eldoc's eldoc-documentation-functions variable.  In Eldoc v1.0.0
        that variable was already available as a way of handling/composing
        multiple docstrings from different sources, but it didn't work
-       practically with mutiple concurrent async sources.  This was fixed in
+       practically with multiple concurrent async sources.  This was fixed in
        1.1.0, which Eglot now requires.
 
        This fixes the synchronization problems reported in 
https://github.com/joaotavora/eglot/issues/494 and also
@@ -109467,7 +109467,7 @@
        use-package--foo--post-config-hook
 
        This should make config customisations more predictable (for example, 
spacemacs
-       uses these hooks extensively to allow 'layers' to be customised).
+       uses these hooks extensively to allow 'layers' to be customized).
 
        I got rid of the "special" default value for :config, because it 
doesn't seem to
        be treated any differently than nil.
@@ -109565,14 +109565,14 @@
 
 2020-05-02  João Távora  <joaotavora@gmail.com>
 
-       Kind of honour eldoc-echo-area-use-multiline-p
+       Kind of honor eldoc-echo-area-use-multiline-p
 
        A reworking of an idea and original implementation by Andrii
        Kolomoiets <andreyk.mad@gmail.com>.  It doesn't honor it completely
        because the semantics for a non-t, non-nil value are tricky.  And we
        don't always exactly know what the symbol prefix reliably.
 
-       * eglot.el (eglot--update-doc): Kind of honour
+       * eglot.el (eglot--update-doc): Kind of honor
        eldoc-echo-area-use-multiline-p.
 
        GitHub-reference: close https://github.com/joaotavora/eglot/issues/443
@@ -110204,7 +110204,7 @@
 
        Support markdown for textdocument/hover ()
 
-       * eglot.el (eglot-client-capabilities): annouce markdown support for 
hover.
+       * eglot.el (eglot-client-capabilities): announce markdown support for 
hover.
        (eglot--format-markup): Format hover info with Markdown.
 
        Fixes: https://github.com/joaotavora/eglot/issues/328
@@ -110401,7 +110401,7 @@
        completion.  When the completion is close to done, the :exit-function
        is called, to potentially rework the inserted text so that the final
        result might be quite different from the proxy (it might be a snippet,
-       or even a suprising text edit).
+       or even a surprising text edit).
 
        The most important change in this commit reworks the way the
        completion "bounds" are calculated in the buffer.  This is the region
@@ -110418,7 +110418,7 @@
        https://github.com/microsoft/language-server-protocol/issues/651, we
        have no choice but to play along with that inneficient and grotesque
        strategy to implement flex-style matching.  Like ever in LSP, we do so
-       while being backward-compatible to all previously supported behaviour.
+       while being backward-compatible to all previously supported behavior.
 
        * eglot.el (eglot-completion-at-point): rework.
 
@@ -110429,8 +110429,8 @@
        Always filter completions client-side by prefix
 
        Prefix completion is all we get in LSP because there are some servers
-       that send *all* completions everytime.  This is horrible, but it's the
-       currently defined behaviour.  See
+       that send *all* completions every time.  This is horrible, but it's the
+       currently defined behavior.  See
        https://github.com/microsoft/language-server-protocol/issues/651.
 
        * eglot.el (eglot-completion-at-point): Use all-completions.
@@ -110584,7 +110584,7 @@
        Unbreak elm language server which does use :triggercharacters
 
        Only query completionProvider -> triggerCharacter information if the
-       server has provided it.  Elm's, and probaly other's, do not provide
+       server has provided it.  Elm's, and probably other's, do not provide
        it, which doesn't mean they don't support completion.
 
        * eglot.el (eglot-completion-at-point): Check that completion
@@ -111371,7 +111371,7 @@
 
        Use eglot--dbind and eglot--lambda throughout
 
-       The default behaviour of these macros is to be lenient towards servers
+       The default behavior of these macros is to be lenient towards servers
        sending unknown keys, which should fix the issue.
 
        * eglot.el (eglot--lsp-interface-alist): Add a bunch of new interfaces.
@@ -111456,7 +111456,7 @@
 
        Support completioncontext to help servers like ccls
 
-       * eglot.el (eglot-client-capabilities): Annouce
+       * eglot.el (eglot-client-capabilities): Announce
        textDocument/completion/contextSupport.
        (eglot--CompletionParams): New helper.
        (eglot-completion-at-point): Use it.
@@ -112024,7 +112024,7 @@
 
        :ensure-system-package was installing packages by running
        system-packages-get-command via async-shell-command. This meant that
-       system-packages-use-sudo wasn't being honoured.
+       system-packages-use-sudo wasn't being honored.
 
        This patch makes :ensure-system-package use system-packages-install
        for all cases, except where a custom install command is supplied, in
@@ -112032,7 +112032,7 @@
 
        This issue was introduced in 9f034a0bcfdd8c4 
[https://github.com/jwiegley/use-package/issues/673], as a fix for
        [https://github.com/jwiegley/use-package/issues/661]. Prior to that 
commit, system-packages-use-sudo was being
-       honoured.
+       honored.
 
        This patch also fixes a bug where a cons containing a lone symbol in a
        list of conses causes nil to used as the package to install.
@@ -112117,7 +112117,7 @@
 
        Ignore extra keys in textdocument/publishdiagnostics ()
 
-       Accoding to the "discussion" in https://reviews.llvm.org/D50571, it
+       According to the "discussion" in https://reviews.llvm.org/D50571, it
        was deemed sufficient that VSCode is fine with the non-standard
        extension -- jt
 
@@ -112277,7 +112277,7 @@
 
        * eglot.el (eglot-sync-connect): New defcustom.
        (eglot-ensure, eglot): Simplify.
-       (eglot--connect): Honour eglot-sync-connect.  Complicate
+       (eglot--connect): Honor eglot-sync-connect.  Complicate
        considerably.
        (eglot-connect-timeout): New defcustom.
        (Package-requires): Require jsonrpc 1.0.6
@@ -112364,7 +112364,7 @@
        requiring command-line invocations that depend on the specific
        momentary environment.
 
-       * eglot.el (eglot-server-programs): CONTACT can be a fucntion of no
+       * eglot.el (eglot-server-programs): CONTACT can be a function of no
        arguments.
        (eglot--guess-contact, eglot--connect): Accept function
        CONTACTs.
@@ -112565,7 +112565,7 @@
 
 2018-07-09  João Távora  <joaotavora@gmail.com>
 
-       Jsonrpc.el is now a gnu elpa depedency
+       Jsonrpc.el is now a gnu elpa dependency
 
        * Makefile (ELFILES): Don't include jsonrpc.
        (jsonrpc-check): Remove target.
@@ -113035,7 +113035,7 @@
 
        Fix indentation f@#$%^ by previous commit
 
-       Courtesy of aggressive-indent-mode... Agressive it is...
+       Courtesy of aggressive-indent-mode... Aggressive it is...
 
 2018-06-09  João Távora  <joaotavora@gmail.com>
 
@@ -113175,7 +113175,7 @@
 
 2018-06-04  João Távora  <joaotavora@gmail.com>
 
-       Support purposedly ignoring a server capability
+       Support purposely ignoring a server capability
 
        * eglot.el (eglot-ignored-server-capabilites): New defcustom.
        (eglot--server-capable): Use it.
@@ -113472,7 +113472,7 @@
 
 2018-05-26  João Távora  <joaotavora@gmail.com>
 
-       Simpify eglot--server-receive
+       Simplify eglot--server-receive
 
        * eglot.el (eglot--obj): Cleanup whitespace.
        (eglot--server-receive): Simplify.
@@ -113854,16 +113854,16 @@
 
        Robustify timer handling for eglot--async-request
 
-       This basically cherry-picks an ealier commit for the jsonrpc-refactor
+       This basically cherry-picks an earlier commit for the jsonrpc-refactor
        branch:
          a2aa1ed..: João Távora 2018-05-18 Robustify timer handling for 
jrpc-async-request
 
        * jrpc.el (jrpc--async-request): Improve timeout handling. Return a 
list (ID TIMER)
-       (jrpc--request): Protect against user-quits, cancelling timer
+       (jrpc--request): Protect against user-quits, canceling timer
 
 2018-05-19  João Távora  <joaotavora@gmail.com>
 
-       Simplify some infrastructure fucntions
+       Simplify some infrastructure functions
 
        * eglot.el (eglot--contact): Simplify docstring.
        (eglot--make-process): Simplify.
@@ -113974,7 +113974,7 @@
 
        Instead of introspecting the :params or :result object to discover if
        an object is present, and changing the Elisp function call type
-       (funcall vs apply) accordingly, alway funcall. It's up to the
+       (funcall vs apply) accordingly, always funcall. It's up to the
        application to destructure if it wishes. jrpc-lambda can help with
        that and keep the application code simple.
 
@@ -114273,7 +114273,7 @@
 
 2018-05-10  João Távora  <joaotavora@gmail.com>
 
-       Prepare to sumbit to gnu elpa
+       Prepare to submit to gnu elpa
 
        * eglot.el: Update headers.
 
@@ -114314,7 +114314,7 @@
        (eglot--TextDocumentIdentifier)
        (eglot--VersionedTextDocumentIdentifier)
        (eglot--TextDocumentPositionParams, eglot--TextDocumentItem):
-       Renamed from the more verbose eglot--current-buffer-* variante.
+       Renamed from the more verbose eglot--current-buffer-* variant.
        (eglot-rename, eglot-imenu, eglot-eldoc-function)
        (eglot-completion-at-point, xref-backend-definitions)
        (xref-backend-identifier-at-point)
@@ -114407,7 +114407,7 @@
 
        Adjust flymake integration
 
-       When opening a new file (signalling textDocument/didOpen) it makes
+       When opening a new file (signaling textDocument/didOpen) it makes
        sense to call the flymake callback (if it exists) with no diagnostics,
        just to get rid of that "Wait", since we don't know if later in this
        callback cycle the server will ever report new diagnostics.
@@ -114822,9 +114822,9 @@
 
 2018-05-04  João Távora  <joaotavora@gmail.com>
 
-       Honour textdocumentsync
+       Honor textdocumentsync
 
-       * eglot.el (eglot--signal-textDocument/didChange): Honour 
textDocumentSync
+       * eglot.el (eglot--signal-textDocument/didChange): Honor 
textDocumentSync
 
 2018-05-04  João Távora  <joaotavora@gmail.com>
 
@@ -115224,7 +115224,7 @@
 
 2018-05-02  João Távora  <joaotavora@gmail.com>
 
-       Change status to error everytime an error is found
+       Change status to error every time an error is found
 
        * eglot.el (eglot--process-receive): Also set error status.
        (eglot--request): Fix a compilation warning.
@@ -116556,7 +116556,7 @@
        (next-overlay-change, previous-overlay-change, overlay-put)
        (overlay-get, report_overlay_modification, evaporate_overlays)
        (init_buffer_once): Adapt to changes and tree data-structure.
-       (overlay-lists, overlay-recenter): Funtions are now obsolete, but
+       (overlay-lists, overlay-recenter): Functions are now obsolete, but
        kept anyway.
        (set_buffer_overlays_before, set_buffer_overlays_after)
        (recenter_overlay_lists,fix_start_end_in_overlays,fix_overlays_before)
@@ -117210,7 +117210,7 @@
 
        This means (use-package foopkg :mode (".foo")) will add (".foo"
        . foopkg) into auto-mode-alist instead of the broken (".foo" . nil),
-       this is more consistent with the behaviour of (use-package foopkg
+       this is more consistent with the behavior of (use-package foopkg
        :mode (".foo" ".bar")).
 
 2016-10-31  Noam Postavsky  <npostavs@gmail.com>
@@ -117678,12 +117678,12 @@
 
        Merge pull request from waymondo/extend-bind-handler
 
-       Pass in symbol of bind macro, for more extensible re-use of same handler
+       Pass in symbol of bind macro, for more extensible reuse of same handler
        GitHub-reference: https://github.com/jwiegley/use-package/issues/259
 
 2015-09-23  Justin Talbott  <justin@waymondo.com>
 
-       pass in symbol of bind macro, for more extensible re-use of same handler
+       pass in symbol of bind macro, for more extensible reuse of same handler
 
        related to https://github.com/jwiegley/use-package/issues/258
 
@@ -118474,7 +118474,7 @@
 
        Lower-priority idle functions are run first. Idle functions with no
        specified priority default to 5 and all functions with the same priority
-       are run in the order in which they are evaluated, meaning the behaviour
+       are run in the order in which they are evaluated, meaning the behavior
        is backwards compatible.
 
        Updated documentation as well.
@@ -118606,7 +118606,7 @@
 
        Merge pull request from aspiers/docs
 
-       Synchronise docs and then remove one copy to prevent future issues.
+       Synchronize docs and then remove one copy to prevent future issues.
        GitHub-reference: https://github.com/jwiegley/use-package/issues/78
 
 2014-01-06  Adam Spiers  <emacs@adamspiers.org>
diff --git a/ChangeLog.android b/ChangeLog.android
index 8cc66c4d7ea..96419ebe351 100644
--- a/ChangeLog.android
+++ b/ChangeLog.android
@@ -700,7 +700,7 @@
        (build-counter.c): New target.  Generate this file using
        makecounter.sh upon changes to lisp.mk or shortlisp.
        (lisp.mk): Make and load relative to abs_top_builddir.
-       (emacs$(EXEEXT)): Adjust acordingly.
+       (emacs$(EXEEXT)): Adjust accordingly.
        (mostlyclean): Remove build-counter.c.
 
 2023-07-18  Po Lu  <luangruo@yahoo.com>
@@ -735,7 +735,7 @@
        prototypes.
 
        * java/org/gnu/emacs/EmacsWindow.java (motionEvent): Set
-       cancelation flag in events sent where appropriate.
+       cancellation flag in events sent where appropriate.
 
        * lisp/touch-screen.el (touch-screen-handle-point-update):
        Improve treatment of horizontal scrolling near window edges.
@@ -749,7 +749,7 @@
        (struct android_touch_event): New field `flags'.
 
        * src/androidterm.c (handle_one_android_event): Report
-       cancelation in TOUCHSCREEN_END_EVENTs.
+       cancellation in TOUCHSCREEN_END_EVENTs.
 
        * src/keyboard.c (make_lispy_event): Fix botched merge.
 
@@ -1005,7 +1005,7 @@
 
        * java/org/gnu/emacs/EmacsWindow.java (Coordinate): New fields
        `button' and `id'.
-       (<init>): Add new arguments to the construtor.
+       (<init>): Add new arguments to the constructor.
        (whatButtonWasIt): Return 0 if the button state has not changed.
        (buttonForEvent): New function.
        (figureChange): Return the Coordinate object associated to EVENT.
@@ -2384,7 +2384,7 @@
        (sfnt_read_avar_table): Fix sequencing problem.
 
        * src/sfntfont.c (sfntfont_setup_interpreter): Don't create
-       interpreter for blatently broken fonts.
+       interpreter for blatantly broken fonts.
        (sfntfont_open): Avoid specifying redundant blends.
 
        * src/sfnt.c (sfnt_validate_gs): Fix validation of projection
@@ -3466,7 +3466,7 @@
        (src/verbose.mk): Depend on verbose.mk.android in srcdir.
        (lib/Makefile): Edit srcdir and VPATH to LIB_SRCDIR.
        (src/Makefile): Edit -I$$(top_srcdir) to -I../$(srcdir)/lib,
-       instead of ommitting it.
+       instead of omitting it.
        (clean): Allow ndk-build clean to fail.
 
        * java/Makefile.in (builddir): New variable.
@@ -3714,7 +3714,7 @@
        module detection.
 
        * src/android.c (android_run_select_thread): Fix typos.
-       (android_run_select_thread): Lock select_mutex before signalling
+       (android_run_select_thread): Lock select_mutex before signaling
        condition variable.
        (android_select): Unlock event queue mutex prior to waiting for
        it.
@@ -4663,7 +4663,7 @@
        (ndk_CONFIG_FILES): Export NDK_BUILD_CFLAGS.
 
        * java/AndroidManifest.xml.in: Prevent the Emacs activity from
-       being overlayed by the emacsclient wrapper.
+       being overlaid by the emacsclient wrapper.
        * java/org/gnu/emacs/EmacsOpenActivity.java (run): Likewise.
        (onCreate): Set an appropriate theme on ICS and up.
 
@@ -5151,7 +5151,7 @@
        * m4/ndk-build.m4 (ndk_package_mape): Add package mapping for
        sqlite3.
 
-       * src/Makefile.in (SQLITE3_CFLAGS): New substition.
+       * src/Makefile.in (SQLITE3_CFLAGS): New substitution.
        (EMACS_CFLAGS): Add that variable.
 
        * src/android.c (android_api_level): New variable.
@@ -5532,7 +5532,7 @@
        (touch-screen-precision-scroll): New user option.
        (touch-screen-handle-scroll): Use traditional scrolling by
        default.
-       (touch-screen-handle-touch): Adust format of
+       (touch-screen-handle-touch): Adjust format of
        touch-screen-current-tool.
        (touch-screen-track-tap): Don't print waiting for events.
        (touch-screen-track-drag): Likewise.  Also, don't call UPDATE
@@ -5555,7 +5555,7 @@
        * lisp/ls-lisp.el (ls-lisp-use-insert-directory-program): Default
        to off on Android.
 
-       * src/android.c (android_is_directory): New fucntion.
+       * src/android.c (android_is_directory): New function.
        (android_fstatat): Handle directories created by
        `android_opendir'.
        (android_open): Return meaningful file mode.
@@ -5645,7 +5645,7 @@
        * java/org/gnu/emacs/EmacsNative.java (EmacsNative): Make all
        event sending functions return long.
 
-       * java/org/gnu/emacs/EmacsPreferencesActivity.java: New fle.
+       * java/org/gnu/emacs/EmacsPreferencesActivity.java: New file.
 
        * java/org/gnu/emacs/EmacsService.java (EmacsService)
        (onStartCommand, onCreate, startEmacsService): Start as a
@@ -6310,7 +6310,7 @@
        and `detectMouse'.
        (struct android_event_queue, android_init_events)
        (android_next_event, android_write_event): Remove write limit.
-       (android_file_access_p): Handle directories correcty.
+       (android_file_access_p): Handle directories correctly.
        (android_close): Fix coding style.
        (android_fclose): New function.
        (android_init_emacs_service): Initialize new methods.
diff --git a/admin/notes/java b/admin/notes/java
index 125ac0aad67..6a66d1aa765 100644
--- a/admin/notes/java
+++ b/admin/notes/java
@@ -15,7 +15,7 @@ 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
+This text exists to prime other Emacs developers, already familiar 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.
 
@@ -570,7 +570,7 @@ Let us go back and review the definition of 
``startEmacsService'':
          context.startService (new Intent (context,
                                            EmacsService.class));
        else
-         /* Display the permanant notification and start Emacs as a
+         /* Display the permanent notification and start Emacs as a
             foreground service.  */
          context.startForegroundService (new Intent (context,
                                                      EmacsService.class));
@@ -796,7 +796,7 @@ Next, `max_handle' is saved, and a new handle is allocated 
for
   if (!window)
     error ("Out of window handles!");
 
-An error is signalled if Emacs runs out of available handles.
+An error is signaled if Emacs runs out of available handles.
 
   if (!class)
     {
diff --git a/configure.ac b/configure.ac
index 759dcd14d50..0224c9c32eb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -306,7 +306,7 @@ AC_DEFUN([OPTION_DEFAULT_OFF], [dnl
 
 dnl OPTION_DEFAULT_IFAVAILABLE(NAME, HELP-STRING)
 dnl Create a new --with option that defaults to 'ifavailable',
-dnl unless it is overriden by $with_features being equal to 'no'.
+dnl unless it is overridden by $with_features being equal to 'no'.
 dnl NAME is the base name of the option.  The shell variable with_NAME
 dnl   will be set to either the user's value (if the option is
 dnl   specified; 'yes' for a plain --with-NAME) or to 'ifavailable' (if the
@@ -5149,6 +5149,11 @@ source on this site:
 
   with_native_compilation=no])
 
+if test "$with_features" = "no" \
+   && test "${with_native_compilation}" = "default"; then
+  with_native_compilation=no
+fi
+
 if test "${with_native_compilation}" = "default"; then
     # Check if libgccjit is available.
     AC_CHECK_LIB([gccjit], [gcc_jit_context_acquire],
diff --git a/cross/ndk-build/README b/cross/ndk-build/README
index aca2e7230bf..d6cf2908014 100644
--- a/cross/ndk-build/README
+++ b/cross/ndk-build/README
@@ -86,7 +86,7 @@ $(ANDROID_MAKEFILE), the ``Android.mk'' file, for the first 
time.  The
 purpose of this evaluation is to establish a list of packages (or
 modules) provided by the ``Android.mk'' file, and the corresponding
 Makefile targets and compiler and linker flags required to build and
-link to those tagets.
+link to those targets.
 
 Before doing so, build-aux/ndk-build-helper.mk will define several
 variables and functions required by all ``Android.mk'' files.  The
@@ -164,7 +164,7 @@ module_cxx_deps=""
 module_imports=""
 
 which is then evaluated by `configure'.         Once the variable
-`module_name' is set, configure apends the remaining
+`module_name' is set, configure appends the remaining
 $(module_includes), $(module_cflags) and $(module_ldflags) to the
 module's CFLAGS and LIBS variables, and appends the list of Makefile
 targets specified to the variable NDK_BUILD_MODULES.
diff --git a/doc/emacs/ChangeLog.1 b/doc/emacs/ChangeLog.1
index 6e20eb942ce..457b33c439f 100644
--- a/doc/emacs/ChangeLog.1
+++ b/doc/emacs/ChangeLog.1
@@ -1294,7 +1294,7 @@
 
        * display.texi (Visual Line Mode): Fix index entry.
 
-       * buffers.texi (Several Buffers): List Buffer Menu command anmes,
+       * buffers.texi (Several Buffers): List Buffer Menu command names,
        and index the keybindings.  Document tabulated-list-sort.
        (Kill Buffer): Capitalize Buffer Menu.
 
@@ -6443,7 +6443,7 @@
 
 2007-01-01  Richard Stallman  <rms@gnu.org>
 
-       * commands.texi (User Input): Document keys stolen by window mangers.
+       * commands.texi (User Input): Document keys stolen by window managers.
 
 2006-12-31  Richard Stallman  <rms@gnu.org>
 
diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index 915ba948b93..3b81f5cb43f 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -234,7 +234,7 @@ Document Providers}.)
 the (normally read-only) root directory named @file{content} or
 @file{assets}, you may want to access real files by these names if the
 Android installation in use has been customized.  These files will
-conflict with the aformentioned special directories, but can
+conflict with the aforementioned special directories, but can
 nevertheless be accessed by writing their names relative to the
 ``parent'' directory of the root directory, as so illustrated:
 @file{/../content}, @file{/../assets}.
@@ -258,7 +258,7 @@ at startup to symlink the application library directory to 
its
 traditional location within the parent of the app data directory.
 
   If Emacs is reinstalled and the location of the app library
-directory consequentially changes, that symlink will also be updated
+directory consequently changes, that symlink will also be updated
 to point to its new location the next time Emacs is started by the
 system.
 
@@ -340,7 +340,7 @@ to its app data directory (@pxref{Android File
 System}.)@footnote{Except in cases where a ``shared user ID'' is
 specified and other applications signed using the same ``package
 signing key'' are installed, in which case Emacs runs as the same user
-and has access to the same files as each of the aformentioned
+and has access to the same files as each of the aforementioned
 applications.}
 
   Each application is also prohibited from accessing many system
@@ -409,6 +409,24 @@ Startup}) connect the Android system to another computer, 
and run:
 $ adb shell "settings put global settings_enable_monitor_phantom_procs false"
 @end example
 
+@cindex system language settings, Android
+  The ``Languages & Input'' preferences which apply to the operating
+system do not influence the C locale set for programs, but are taken
+into account by Emacs during startup: a locale name is generated from
+the selected language and regional variant and a language environment
+(@pxref{Language Environments}) is selected on that basis, which does
+not overwrite @code{LANG} or other locale-related environment
+variables.  The coding system for language environments set in this
+fashion is @code{utf-8-unix} without exception.
+
+@cindex C locale settings, Android
+  Instead, the @code{LANG} environment variable (@pxref{General
+Variables}) is set to @code{en_US.utf8} when Emacs starts on Android
+5.0 or newer, which induces subprocesses linked against the Android C
+library to print output sensibly.  Earlier versions of Android do not
+implement locales at all, and on that account, the variable is set to
+@code{C}.
+
 @cindex running emacs in the background, android
 @cindex emacs killed, android
 @cindex emacs in the background, android
diff --git a/doc/emacs/cmdargs.texi b/doc/emacs/cmdargs.texi
index 38e683bd7f5..7cdc29ea30b 100644
--- a/doc/emacs/cmdargs.texi
+++ b/doc/emacs/cmdargs.texi
@@ -640,6 +640,11 @@ set this in the ``Regional Settings'' Control Panel on 
some versions
 of MS-Windows, and in the ``Language and Region'' System Preference on
 macOS.
 
+When running a GUI session on Android, @env{LANG} is set to a fixed
+value, but the language and locale environment is derived from the
+system's ``Languages & Input'' preferences.  @xref{Android
+Environment}.
+
 The value of the @env{LC_CTYPE} category is
 matched against entries in @code{locale-language-names},
 @code{locale-charset-language-names}, and
diff --git a/doc/emacs/dired.texi b/doc/emacs/dired.texi
index 87124e962ca..6089cfe833d 100644
--- a/doc/emacs/dired.texi
+++ b/doc/emacs/dired.texi
@@ -142,6 +142,10 @@ characters well.  If you have many such files, you may 
consider adding
 special characters and allow Dired to handle them better.  (You can
 also use the @kbd{C-u C-x d} command to add @samp{-b} temporarily.)
 
+@code{dired-listing-switches} can be declared as connection-local
+variable to adjust it to match what a remote system expects
+(@pxref{Connection Variables}).
+
 @vindex dired-switches-in-mode-line
   Dired displays in the mode line an indication of what were the
 switches used to invoke @command{ls}.  By default, Dired will try to
diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 917e937d32d..832c189ce49 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -1329,6 +1329,10 @@ directory listing describing the specified file and the 
auto-save file,
 so you can compare their sizes and dates.  If the auto-save file
 is older, @kbd{M-x recover-file} does not offer to read it.
 
+When @kbd{M-x recover-file} asks for confirmation, if you answer with
+@kbd{diff} or @kbd{=}, it shows the diffs between @var{file} and its
+auto-save file @file{#@var{file}#} and reprompts you for confirmation.
+
 @findex recover-session
   If Emacs or the computer crashes, you can recover all the files you
 were editing from their auto save files with the command @kbd{M-x
diff --git a/doc/emacs/haiku.texi b/doc/emacs/haiku.texi
index 0bb216c14ae..e129fd6f33f 100644
--- a/doc/emacs/haiku.texi
+++ b/doc/emacs/haiku.texi
@@ -10,7 +10,7 @@ re-implementation of the operating system BeOS.
 
   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
+idiosyncrasies illustrated here do not apply to Emacs on Haiku built
 without windowing support, or configured with X11.
 
 @menu
diff --git a/doc/lispintro/emacs-lisp-intro.texi 
b/doc/lispintro/emacs-lisp-intro.texi
index d6627a2a1ca..eb8ff413b79 100644
--- a/doc/lispintro/emacs-lisp-intro.texi
+++ b/doc/lispintro/emacs-lisp-intro.texi
@@ -14630,7 +14630,7 @@ almost the same code as for the recursive version of
 
 @need 800
 @noindent
-Let's re-use @kbd{C-c =} as a convenient key binding:
+Let's reuse @kbd{C-c =} as a convenient key binding:
 
 @smallexample
 (global-set-key "\C-c=" 'count-words-defun)
diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi
index f6462a9e50b..b4226a9ec6f 100644
--- a/doc/lispref/commands.texi
+++ b/doc/lispref/commands.texi
@@ -2151,7 +2151,7 @@ is dismissed (@pxref{Mouse Menus}), Emacs also avoids 
simple
 translation if @code{down-mouse-1} is bound to a keymap, making it a
 prefix key.  In lieu of simple translation, it translates the closing
 @code{touchscreen-end} to a @code{down-mouse-1} event with the
-starting position of the touch sequence, consequentially displaying
+starting position of the touch sequence, consequently displaying
 the mouse menu.
 
 @cindex @code{mouse-1-menu-command}, a symbol property
@@ -2205,7 +2205,7 @@ position of the touchpoint.
 @item (touchscreen-restart-drag @var{posn})
 This event is sent upon the start of a touch sequence resulting in the
 continuation of a ``drag-to-select'' gesture (subject to the
-aformentioned user option) with @var{posn} set to the position list of
+aforementioned user option) with @var{posn} set to the position list of
 the initial @code{touchscreen-begin} event within that touch sequence.
 
 @cindex @code{touchscreen-pinch} event
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 4dbb4afb20d..8ad8b04f908 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -2726,7 +2726,7 @@ Draw a box with lines of width 1, in color @var{color}.
 You can explicitly specify all aspects of the box with a plist on this
 form.  Any element in this plist can be omitted.
 
-The values @var{vwidth} and @var{hwidth} specifies respectively the
+The values of @var{vwidth} and @var{hwidth} specify respectively the
 width of the vertical and horizontal lines to draw; they default to (1
 . 1).  A negative horizontal or vertical width @minus{}@var{n} means
 to draw a line of width @var{n} that occupies the space of the
@@ -2735,16 +2735,16 @@ width. For simplification the width could be specified 
with only a
 single number @var{n} instead of a list, such case is equivalent to
 @code{((abs @var{n}) . @var{n})}.
 
-The value @var{style} specifies whether to draw a 3D box.  If it is
+The value of @var{color} specifies the color to draw with.  The default
+is the background color of the face for 3D boxes and
+@code{flat-button}, and the foreground color of the face for other
+boxes.
+
+The value of @var{style} specifies whether to draw a 3D box.  If it is
 @code{released-button}, the box looks like a 3D button that is not
 being pressed.  If it is @code{pressed-button}, the box looks like a
 3D button that is being pressed.  If it is @code{nil},
 @code{flat-button} or omitted, a plain 2D box is used.
-
-The value @var{color} specifies the color to draw with.  The default
-is the background color of the face for 3D boxes and
-@code{flat-button}, and the foreground color of the face for other
-boxes.
 @end table
 
 @item :inverse-video
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index dc66ea8bc9c..d6ef7fe4e31 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -1871,9 +1871,10 @@ multiple names, it continues to exist under the other 
names.  If
 @var{filename} is a symbolic link, @code{delete-file} deletes only the
 symbolic link and not its target.
 
-A suitable kind of @code{file-error} error is signaled if the file
-does not exist, or is not deletable.  (On GNU and other POSIX-like
-systems, a file is deletable if its directory is writable.)
+The command signals a suitable kind of @code{file-error} error if
+@var{filename} cannot be deleted.  (On GNU and other POSIX-like
+systems, a file can be deleted if its directory is writable.)  If the
+file does not exist, this command will not signal any error.
 
 If the optional argument @var{trash} is non-@code{nil} and the
 variable @code{delete-by-moving-to-trash} is non-@code{nil}, this
diff --git a/doc/lispref/frames.texi b/doc/lispref/frames.texi
index ec6f7fd9462..f6f9e56e0c7 100644
--- a/doc/lispref/frames.texi
+++ b/doc/lispref/frames.texi
@@ -4160,7 +4160,7 @@ code, for it's only meant to abet synchronization between 
the X
 server, owner and requestor.
 @end itemize
 
-  The selection owner responds by tranferring to the requestor a
+  The selection owner responds by transferring to the requestor a
 series of bytes, 16 bit words, or 32 bit words, along with another
 atom identifying the type of those words.  After requesting a
 selection, Emacs then applies its own interpretation of the data
@@ -4514,7 +4514,7 @@ bounds of the selection data in the buffer @var{buf}.
   Selections under such window systems as MS-Windows, Nextstep, Haiku
 and Android are not aligned with those under X@.  Each of these window
 system improvises its own selection mechanism without employing the
-``selection converter'' mechanism illustrated in the preceeding node.
+``selection converter'' mechanism illustrated in the preceding node.
 Only the @code{PRIMARY}, @code{CLIPBOARD}, and @code{SECONDARY}
 selections are generally supported, with the @code{XdndSelection}
 selection that records drag-and-drop data also available under
@@ -4852,7 +4852,7 @@ is the selection data itself (@pxref{Accessing 
Selections}).
 sometimes distinct from those provided by the ICCCM and conforming
 clipboard or primary selection owners.  Frequently, the name of a MIME
 type, such as @code{"text/plain;charset=utf-8"} (with discrepant
-capitalization of the ``utf-8''), is substitued for a standard X
+capitalization of the ``utf-8''), is substituted for a standard X
 selection name such as @code{UTF8_STRING}.
 
 @cindex XDS
diff --git a/doc/lispref/functions.texi b/doc/lispref/functions.texi
index ba0d919549b..d0c8f3e90e8 100644
--- a/doc/lispref/functions.texi
+++ b/doc/lispref/functions.texi
@@ -533,6 +533,40 @@ Instead, use the @code{advertised-calling-convention} 
declaration
 compiler emit a warning message when it compiles Lisp programs which
 use the deprecated calling convention.
 
+@ifnottex
+The @code{(fn)} feature is typically used in the following situations:
+
+@itemize @minus
+@item To spell out arguments and their purposes in a macro or a function.  
Example:
+
+@example
+(defmacro lambda (&rest cdr)
+  "@dots{}
+\(fn ARGS [DOCSTRING] [INTERACTIVE] BODY)"@dots{})
+@end example
+
+@item To provide a more detailed description and names of arguments.  Example:
+
+@example
+(defmacro macroexp--accumulate (var+list &rest body)
+  "@dots{}
+\(fn (VAR LIST) BODY@dots{})"
+  (declare (indent 1))
+  (let ((var (car var+list))
+         (list (cadr var+list))
+@dots{})))
+@end example
+
+@item To better explain the purpose of a @code{defalias}.  Example:
+
+@example
+(defalias 'abbrev-get 'get
+  "@dots{}
+\(fn ABBREV PROP)")
+@end example
+@end itemize
+@end ifnottex
+
 @cindex computed documentation string
 @kindex :documentation
 Documentation strings are usually static, but occasionally it can be
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi
index d4b1c4f2b3e..bdc3b7307cf 100644
--- a/doc/lispref/keymaps.texi
+++ b/doc/lispref/keymaps.texi
@@ -491,7 +491,7 @@ useful if there is a command which doesn't exist in the map 
being
 defined, but which should have the @code{repeat-map} property.
 
 If the @code{:exit} list is empty then no commands in the map exit
-@code{repeat-mode}.  Specifying one ore more commands in this list is
+@code{repeat-mode}.  Specifying one or more commands in this list is
 useful if the keymap being defined contains a command that should not
 have the @code{repeat-map} property.
 @end table
diff --git a/doc/lispref/minibuf.texi b/doc/lispref/minibuf.texi
index ba7f1ca692e..03c221c6cf6 100644
--- a/doc/lispref/minibuf.texi
+++ b/doc/lispref/minibuf.texi
@@ -1564,7 +1564,7 @@ Interactively, or when @var{display} is non-@code{nil}, 
the return
 value is also displayed in the echo area.
 
 The optional arguments @var{foreground} and @var{face} control the
-appearence of the completion candidates in the @file{*Completions*}
+appearance of the completion candidates in the @file{*Completions*}
 buffer.  The candidates are displayed in the specified @var{face} but
 with different colors: if @var{foreground} is non-@code{nil}, the
 foreground color is changed to be the color of the candidate,
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index df81a805e67..36238c1e1d7 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -1071,8 +1071,8 @@ This function returns the field name of the @var{n}'th 
child of
 @var{node}.  It returns @code{nil} if there is no @var{n}'th child, or
 the @var{n}'th child doesn't have a field name.
 
-Note that @var{n} counts both named and anonymous children, and
-@var{n} can be negative, e.g., @minus{}1 represents the last child.
+Note that @var{n} counts named nodes only, and @var{n} can be
+negative, e.g., @minus{}1 represents the last child.
 @end defun
 
 @defun treesit-node-child-count node &optional named
diff --git a/doc/lispref/processes.texi b/doc/lispref/processes.texi
index 887b41d0005..976ea1e46bc 100644
--- a/doc/lispref/processes.texi
+++ b/doc/lispref/processes.texi
@@ -2639,7 +2639,7 @@ and @samp{:capability-command} are supplied, try to 
upgrade to an encrypted
 connection via @acronym{STARTTLS}.  If that fails, retain the
 unencrypted connection.
 @item starttls
-As for @code{nil}, but if @acronym{STARTTLS} fails drop the connection.
+As for @code{nil}, but if @acronym{STARTTLS} fails, drop the connection.
 @item shell
 A shell connection.
 @end table
@@ -2650,9 +2650,9 @@ doing a @samp{plain} connection.
 
 @item :capability-command @var{capability-command}
 Command to query the host capabilities.  This can either be a string
-(which will then be sent verbatim to the server), or a function
-(called with a single parameter; the "greeting" from the server when
-connecting), and should return a string.
+(which will then be sent verbatim to the server) or a function
+(called with a single parameter: the ``greeting'' from the server when
+connecting) that should return a string.
 
 @item :end-of-command @var{regexp}
 @itemx :end-of-capability @var{regexp}
@@ -2661,8 +2661,8 @@ command @var{capability-command}.  The latter defaults to 
the former.
 
 @item :starttls-function @var{function}
 Function of one argument (the response to @var{capability-command}),
-which returns either @code{nil}, or the command to activate @acronym{STARTTLS}
-if supported.
+which returns either @code{nil} or the command to activate
+@acronym{STARTTLS}, if supported.
 
 @item :success @var{regexp}
 Regular expression matching a successful @acronym{STARTTLS} negotiation.
@@ -2690,8 +2690,9 @@ enable automatic queries of @code{auth-source} when
 
 @item :return-list @var{cons-or-nil}
 The return value of this function.  If omitted or @code{nil}, return a
-process object.  Otherwise, a cons of the form @code{(@var{process-object}
-. @var{plist})}, where @var{plist} has keywords:
+process object.  Otherwise, a cons of the form
+@w{@code{(@var{process-object} . @var{plist})}}, where @var{plist} can
+include the following keywords:
 
 @table @code
 @item :greeting @var{string-or-nil}
@@ -2704,11 +2705,12 @@ The connection type: @samp{plain} or @samp{tls}.
 
 @item :shell-command @var{string-or-nil}
 If the connection @code{type} is @code{shell}, this parameter will be
-interpreted as a format-spec string that will be executed to make the
-connection.  The specs available are @samp{%s} for the host name and
-@samp{%p} for the port number.  For instance, if you want to first ssh
-to @samp{gateway} before making a plain connection, then this
-parameter could be something like @samp{ssh gateway nc %s %p}.
+interpreted as a format-spec string (@pxref{Custom Format Strings})
+that will be executed to make the connection.  The specs available are
+@samp{%s} for the host name and @samp{%p} for the port number.  For
+instance, if you want to first ssh to @samp{gateway} before making a
+plain connection, then this parameter's value could be something like
+@samp{ssh gateway nc %s %p}.
 
 @end table
 
diff --git a/doc/lispref/searching.texi b/doc/lispref/searching.texi
index cb269fcacc5..1a898828eb1 100644
--- a/doc/lispref/searching.texi
+++ b/doc/lispref/searching.texi
@@ -2990,7 +2990,7 @@ values of the variables @code{sentence-end-double-space}
 @section Emacs versus POSIX Regular Expressions
 @cindex POSIX regular expressions
 
-Regular expression syntax varies signficantly among computer programs.
+Regular expression syntax varies significantly among computer programs.
 When writing Elisp code that generates regular expressions for use by other
 programs, it is helpful to know how syntax variants differ.
 To give a feel for the variation, this section discusses how
diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 5d05ef18d4f..e35d449ca6d 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -5919,74 +5919,109 @@ Nevertheless, we can define two distinct APIs around 
the
 @cindex JSONRPC application interfaces
 @enumerate
 
-@item A user interface for building JSONRPC applications
+@item An API for building JSONRPC applications
 
 @findex :request-dispatcher
 @findex :notification-dispatcher
 @findex jsonrpc-notify
 @findex jsonrpc-request
 @findex jsonrpc-async-request
-In this scenario, the JSONRPC application selects a concrete subclass
-of @code{jsonrpc-connection}, and proceeds to create objects of that
-subclass using @code{make-instance}.  To initiate a contact to the
-remote endpoint, the JSONRPC application passes this object to the
-functions @code{jsonrpc-notify}, @code{jsonrpc-request}, and/or
-@code{jsonrpc-async-request}.  For handling remotely initiated
-contacts, which generally come in asynchronously, the instantiation
-should include @code{:request-dispatcher} and
-@code{:notification-dispatcher} initargs, which are both functions of
-3 arguments: the connection object; a symbol naming the JSONRPC method
-invoked remotely; and a JSONRPC @code{params} object.
+In this scenario, a new aspiring JSONRPC-based application selects a
+concrete subclass of @code{jsonrpc-connection} that provides the
+transport for the JSONRPC messages to be exchanged between endpoints.
+
+The application creates objects of that subclass using
+@code{make-instance}.  To initiate a contact to a remote endpoint, the
+application passes this object to the functions such as
+@code{jsonrpc-notify}, @code{jsonrpc-request}, or
+@code{jsonrpc-async-request}.
+
+For handling remotely initiated contacts, which generally come in
+asynchronously, the @code{make-instance} instantiation should
+initialize it the @code{:request-dispatcher} and
+@code{:notification-dispatcher} EIEIO keyword arguments.  These are
+both functions of 3 arguments: the connection object; a symbol naming
+the JSONRPC method invoked remotely; and a JSONRPC @code{params}
+object.
 
 @findex jsonrpc-error
 The function passed as @code{:request-dispatcher} is responsible for
 handling the remote endpoint's requests, which expect a reply from the
-local endpoint (in this case, the program you're building).  Inside
-that function, you may either return locally (a normal return) or
-non-locally (an error return).  A local return value must be a Lisp
-object that can be serialized as JSON (@pxref{Parsing JSON}).  This
-determines a success response, and the object is forwarded to the
-server as the JSONRPC @code{result} object.  A non-local return,
-achieved by calling the function @code{jsonrpc-error}, causes an error
-response to be sent to the server.  The details of the accompanying
-JSONRPC @code{error} are filled out with whatever was passed to
+local endpoint (in this case, the application you're building).
+Inside that function, you may either return locally (a regular return)
+or non-locally (throw an error).  Both exits from the request
+dispatcher cause a reply to the remote endpoint's request to be sent
+through the transport.
+
+A regular return determines a success response, and the return value
+must be a Lisp object that can be serialized as JSON (@pxref{Parsing
+JSON}).  The result is forwarded to the server as the JSONRPC
+@code{result} object.  A non-local return, achieved by calling the
+function @code{jsonrpc-error}, causes an error response to be sent to
+the server.  The details of the accompanying JSONRPC @code{error}
+object are filled out with whatever was passed to
 @code{jsonrpc-error}.  A non-local return triggered by an unexpected
 error of any other type also causes an error response to be sent
 (unless you have set @code{debug-on-error}, in which case this calls
 the Lisp debugger, @pxref{Error Debugging}).
 
-@item A inheritance interface for building JSONRPC transport implementations
-
-In this scenario, @code{jsonrpc-connection} is subclassed to implement
+@findex jsonrpc-convert-to-endpoint
+@findex jsonrpc-convert-from-endpoint
+It's possible to use the @code{jsonrpc} library to build applications
+based on transport protocols that can be described as
+``quasi-JSONRPC''.  These are similar, but not quite identical to
+JSONRPC, such as the @uref{https://www.jsonrpc.org/, DAP (Debug
+Adapter Protocol)}.  These protocols also define request, response and
+notification messages but the format is not quite the same as JSONRPC.
+The generic functions @code{jsonrpc-convert-to-endpoint} and
+@code{jsonrpc-convert-from-endpoint} can be customized for converting
+between the internal representation of JSONRPC and whatever the
+endpoint accepts (@pxref{Generic Functions}).
+
+@item An API for building JSONRPC transports
+
+In this scenario, @code{jsonrpc-connection} is sub-classed to implement
 a different underlying transport strategy (for details on how to
 subclass, see @ref{Inheritance,Inheritance,,eieio}.).  Users of the
 application-building interface can then instantiate objects of this
 concrete class (using the @code{make-instance} function) and connect
-to JSONRPC endpoints using that strategy.
+to JSONRPC endpoints using that strategy.  See @ref{Process-based
+JSONRPC connections} for a built-in transport implementation.
 
 This API has mandatory and optional parts.
 
 @findex jsonrpc-connection-send
 To allow its users to initiate JSONRPC contacts (notifications or
-requests) or reply to endpoint requests, the subclass must have an
-implementation of the @code{jsonrpc-connection-send} method.
+requests) or reply to endpoint requests, the new transport
+implementation must equip the @code{jsonrpc-connection-send} generic
+function with a specialization for the the new subclass
+(@pxref{Generic Functions}).  This generic function is called
+automatically by primitives such as @code{jsonrpc-request} and
+@code{jsonrpc-notify}.  The specialization should ensure that the
+message described in the argument list is sent through whatever
+underlying communication mechanism (a.k.a.@: ``wire'') is used by the
+new transport to talk to endpoints.  This ``wire'' may be a network
+socket, a serial interface, an HTTP connection, etc.
 
 @findex jsonrpc-connection-receive
 Likewise, for handling the three types of remote contacts (requests,
 notifications, and responses to local requests), the transport
 implementation must arrange for the function
-@code{jsonrpc-connection-receive} to be called after noticing a new
-JSONRPC message on the wire (whatever that "wire" may be).
+@code{jsonrpc-connection-receive} to be called from Elisp after
+noticing some data on the ``wire'' that can be used to craft a JSONRPC
+(or quasi-JSONRPC) message.
 
 @findex jsonrpc-shutdown
 @findex jsonrpc-running-p
 Finally, and optionally, the @code{jsonrpc-connection} subclass should
-implement the @code{jsonrpc-shutdown} and @code{jsonrpc-running-p}
-methods if these concepts apply to the transport.  If they do, then
-any system resources (e.g.@: processes, timers, etc.) used to listen for
-messages on the wire should be released in @code{jsonrpc-shutdown},
-i.e.@: they should only be needed while @code{jsonrpc-running-p} is
-non-@code{nil}.
+add specializations to the @code{jsonrpc-shutdown} and
+@code{jsonrpc-running-p} generic functions if these concepts apply to
+the transport.  The specialization of @code{jsonrpc-shutdown} should
+ensure the release of any system resources (e.g.@: processes, timers,
+etc.) used to listen for messages on the wire.  The specialization of
+@code{jsonrpc-running-p} should tell if these resources are still
+active or have already been released (via @code{jsonrpc-shutdown} or
+otherwise).
 
 @end enumerate
 
@@ -6205,7 +6240,7 @@ cons it was set to at the time 
@code{prepare-change-group} was called.
 
   If @code{buffer-undo-list} no longer contains that cons, Emacs will
 lose track of any change groups, resulting in an error when the change
-group is cancelled.  To avoid this, do not call any functions which
+group is canceled.  To avoid this, do not call any functions which
 may edit the undo list in such a manner, when a change group is
 active: notably, ``amalgamating'' commands such as @code{delete-char},
 which call @code{undo-auto-amalgamate}.
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index f575b188fc6..336a776bdc4 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -2487,9 +2487,10 @@ are unwound.  Example:
 
 @defvar connection-local-default-application
 The default application, a symbol, to be applied in
-@code{with-connection-local-variables}.  It defaults to @code{tramp},
-but you can let-bind it to change the application temporarily
-(@pxref{Local Variables}).
+@code{with-connection-local-variables}, @code{connection-local-p} and
+@code{connection-local-value}.  It defaults to @code{tramp}, but you
+can let-bind it to change the application temporarily (@pxref{Local
+Variables}).
 
 This variable must not be changed globally.
 @end defvar
@@ -2545,6 +2546,22 @@ profile.
 This variable must not be changed globally.
 @end defvar
 
+@defmac connection-local-p symbol &optional application
+This macro returns non-@code{nil} if @var{symbol} has a
+connection-local binding for @var{application}.  If @var{application}
+is @code{nil}, the value of
+@code{connection-local-default-application} is used.
+@end defmac
+
+@defmac connection-local-value symbol &optional application
+This macro returns the connection-local value of @var{symbol} for
+@var{application}.  If @var{application} is @code{nil}, the value of
+@code{connection-local-default-application} is used.
+
+If @var{symbol} does not have a connection-local
+binding, the value is the default binding of the variable.
+@end defmac
+
 @defvar enable-connection-local-variables
 If @code{nil}, connection-local variables are ignored.  This variable
 shall be changed temporarily only in special modes.
@@ -2985,7 +3002,7 @@ meant to be used, here's a small example:
 
 @lisp
 @group
-(define-multisession-variable foo-var 0)
+(define-multisession-variable foo 0)
 (defun my-adder (num)
   (interactive "nAdd number: ")
   (setf (multisession-value foo)
@@ -2995,7 +3012,7 @@ meant to be used, here's a small example:
 @end lisp
 
 @noindent
-This defines the variable @code{foo-var} and binds it to a special
+This defines the variable @code{foo} and binds it to a special
 multisession object which is initialized with the value @samp{0} (if
 the variable doesn't already exist from a previous session).  The
 @code{my-adder} command queries the user for a number, adds this to
@@ -3018,7 +3035,7 @@ specified by @var{package-symbol}.  The combination of
 @var{package-symbol} isn't given, this will default to the first
 ``segment'' of the @var{name} symbol's name, which is the part of its
 name up to and excluding the first @samp{-}.  For instance, if
-@var{name} is @code{foo-var} and @var{package-symbol} isn't given,
+@var{name} is @code{foo} and @var{package-symbol} isn't given,
 @var{package-symbol} will default to @code{foo}.
 
 @cindex synchronized multisession variables
@@ -3026,7 +3043,7 @@ name up to and excluding the first @samp{-}.  For 
instance, if
 Multisession variables can be @dfn{synchronized} if @var{bool} is
 non-@code{nil}.  This means that if there're two concurrent Emacs
 instances running, and the other Emacs changes the multisession
-variable @code{foo-var}, the current Emacs instance will retrieve that
+variable @code{foo}, the current Emacs instance will retrieve that
 modified data when accessing the value.  If @var{synchronized} is
 @code{nil} or missing, this won't happen, and the values in all
 Emacs sessions using the variable will be independent of each other.
diff --git a/doc/lispref/windows.texi b/doc/lispref/windows.texi
index 22c1b307252..b11f6d4f3ab 100644
--- a/doc/lispref/windows.texi
+++ b/doc/lispref/windows.texi
@@ -3268,6 +3268,15 @@ The value specifies an alist of frame parameters to give 
a new frame,
 if one is created.  @code{display-buffer-pop-up-frame} is its one and
 only addressee.
 
+@vindex pop-up-frames@r{, a buffer display action alist entry}
+@item pop-up-frames
+The value controls whether @code{display-buffer} may display buffers
+by making new frames.  It has the same meaning as the
+@code{pop-up-frames} variable and takes precedence over it when present.
+Its main intended purpose is to override a non-nil value of the
+variable for particular buffers which the user prefers to keep
+in the selected frame.
+
 @vindex parent-frame@r{, a buffer display action alist entry}
 @item parent-frame
 The value specifies the parent frame to be used when the buffer is
@@ -3441,6 +3450,9 @@ A non-@code{nil} value also means that when 
@code{display-buffer} is
 looking for a window already displaying @var{buffer-or-name}, it can
 search any visible or iconified frame, not just the selected frame.
 
+An entry by the same name in @code{display-buffer}'s @var{alist}
+takes precedence over the variable.
+
 This variable is provided mainly for backward compatibility.  It is
 obeyed by @code{display-buffer} via a special mechanism in
 @code{display-buffer-fallback-action}, which calls the action function
@@ -3512,15 +3524,12 @@ functions it should try instead as, for example:
 
 @item pop-up-frames
 @vindex pop-up-frames@r{, replacement for}
-Instead of customizing this variable to @code{t}, customize
+Instead of customizing this variable to @code{t}, you can customize
 @code{display-buffer-base-action}, for example, as follows:
 
 @example
 @group
-(setopt
- display-buffer-base-action
- '((display-buffer-reuse-window display-buffer-pop-up-frame)
-   (reusable-frames . 0)))
+(setopt display-buffer-base-action '(nil (pop-up-frames . t)))
 @end group
 @end example
 
diff --git a/doc/misc/ChangeLog.1 b/doc/misc/ChangeLog.1
index 832dbd846a6..f8f2d27b723 100644
--- a/doc/misc/ChangeLog.1
+++ b/doc/misc/ChangeLog.1
@@ -6011,7 +6011,7 @@
        (RSS Feeds): New section.
        (Built-in table editor): Document M-e and M-a navigate
        inside table field.
-       (Stuck projects): Docment that projects identified as
+       (Stuck projects): Document that projects identified as
        un-stuck will still be searched for stuck sub-projects.
        (Paragraphs): Document centering.
        (Creating timestamps, Agenda commands): Document new
diff --git a/doc/misc/calc.texi b/doc/misc/calc.texi
index c651b007173..7e9ba59d008 100644
--- a/doc/misc/calc.texi
+++ b/doc/misc/calc.texi
@@ -11954,7 +11954,7 @@ trail pointer in various ways.
 @cindex Retrieving previous results
 The @kbd{t y} (@code{calc-trail-yank}) command reads the selected value in
 the trail and pushes it onto the Calculator stack.  It allows you to
-re-use any previously computed value without retyping.  With a numeric
+reuse any previously computed value without retyping.  With a numeric
 prefix argument @var{n}, it yanks the value @var{n} lines above the current
 trail pointer.
 
diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index 2d6fcb29d3f..eda93d84aff 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -138,11 +138,10 @@ Turn on Eglot for your project.
 To start using Eglot for a project, type @kbd{M-x eglot @key{RET}} in
 a buffer visiting any file that belongs to the project.  This starts
 the language server configured for the programming language of that
-buffer, and causes Eglot to start managing all the files of the
-project which use the same programming language.  This includes files
-of a given project that are already visited at the time the
-@code{eglot} command is invoked as well as files visited after this
-invocation.
+buffer, and causes Eglot to start @dfn{managing} file-visiting buffers
+related to that programming language.  This includes files that are
+already visited at the time the @code{eglot} command is invoked, as
+well as any files visited after this invocation.
 
 The notion of a ``project'' used by Eglot is the same Emacs uses
 (@pxref{Projects,,, emacs, GNU Emacs Manual}): in the simplest case,
@@ -405,11 +404,13 @@ commands and variables.
 @section Eglot Features
 @cindex features in buffers supported by Eglot
 
-Once Eglot is enabled in a buffer, it uses LSP and the language-server
-capabilities to activate, enable, and enhance modern IDE features in
-Emacs.  The features themselves are usually provided via other Emacs
-packages.  Here's the list of the main features that Eglot enables and
-provides:
+While Eglot is enabled in a buffer, it is said to be @dfn{managing}
+it, using LSP and the specific capabilities of the language server to
+activate and enhance modern IDE features in Emacs.  Some of these
+features are provided via other Emacs packages, and some via Eglot
+directly (@pxref{Eglot Commands}).
+
+Here's an overview of the main features that Eglot provides:
 
 @itemize @bullet
 @item
@@ -422,10 +423,11 @@ allows major modes to provide extensive help and 
documentation about
 the program identifiers.
 
 @item
-On-the-fly diagnostic annotations with server-suggested fixes, via the
-Flymake package (@pxref{Top,,, flymake, GNU Flymake manual}).  This
-improves and enhances the Flymake diagnostics, replacing the other
-Flymake backends.
+On-the-fly diagnostic annotations, via the Flymake package
+(@pxref{Top,,, flymake, GNU Flymake manual}).  Eglot's Flymake backend
+replaces other Flymake backends while it is managing a buffer, and
+enhances diagnostics with interactive server-suggested fixes
+(so-called @dfn{code actions}, @pxref{Eglot Commands})
 
 @item
 Finding definitions and uses of identifiers, via Xref (@pxref{Xref,,,
@@ -484,9 +486,17 @@ with @kbd{eglot-code-actions}.  @xref{Eglot Commands}.
 
 Not all servers support the full set of LSP capabilities, but most of
 them support enough to enable the basic set of features mentioned
-above.  Conversely, some servers offer capabilities for which no
-equivalent Emacs package exists yet, and so Eglot cannot (yet) expose
-these capabilities to Emacs users.
+above.
+
+Conversely, some servers offer capabilities for which no equivalent
+Emacs package exists yet, and so Eglot cannot (yet) expose these
+capabilities to Emacs users.  However, @xref{Extending Eglot}.
+
+Finally, it's worth noting that, by default, Eglot generally turns on
+all features that it @emph{can} turn on.  It's possible to opt out of
+some features via user options (@pxref{Customizing Eglot}) and a hook
+that runs after Eglot starts managing a buffer (@pxref{Eglot and
+Buffers}).
 
 @node Eglot and Buffers
 @section Buffers, Projects, and Eglot
@@ -694,7 +704,7 @@ requests for the language server to provide editing 
commands for
 correcting, refactoring or beautifying your code.  These commands may
 affect more than one visited file belonging to the project.
 
-The command @code{eglot-code-actions} asks the server if there any
+The command @code{eglot-code-actions} asks the server if there are any
 code actions for any point in the buffer or contained in the active
 region.  If there are, you have the choice to execute one of them via
 the minibuffer.
@@ -1222,7 +1232,7 @@ in @ref{Project-specific configuration}.  Here is an 
example:
 @end lisp
 
 Note that the global value of @code{eglot-workspace-configuration} is
-always overriden if a directory-local value is detected.
+always overridden if a directory-local value is detected.
 
 @node JSONRPC objects in Elisp
 @section JSONRPC objects in Elisp
diff --git a/doc/misc/epa.texi b/doc/misc/epa.texi
index 1aeaef8990f..b7aff0077e6 100644
--- a/doc/misc/epa.texi
+++ b/doc/misc/epa.texi
@@ -456,9 +456,9 @@ public key, it does not prompt for a passphrase for the 
buffer save,
 but it will prompt for your passphrase for file reads every now and
 then, depending on the GnuPG Agent cache configuration.
 
-@cindex tempory files created by easypg assistant
+@cindex temporary files created by easypg assistant
 To encrypt and decrypt files as described above EasyPG Assistant under
-certain circumstances uses intermediate tempory files that contain the
+certain circumstances uses intermediate temporary files that contain the
 plain-text contents of the files it processes.  EasyPG Assistant
 creates them below the directory returned by function
 @code{temporary-file-directory} (@pxref{Unique File Names, ,
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index d7260ffa329..131e02555d1 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -918,16 +918,11 @@ In the latter case, if the first nick in the list is 
already in use,
 other nicks are tried in the list order.
 @end defopt
 
-@defopt erc-format-nick-function
-A function to format a nickname for message display
-
-You can set this to @code{erc-format-@@nick} to display user mode prefix
+@defopt erc-show-speaker-membership-status
+A boolean for including a channel member's @dfn{status prefix} in
+their display name when they speak.
 @end defopt
 
-@example
-(setq erc-format-nick-function 'erc-format-@@nick)
-@end example
-
 @defopt erc-nick-uniquifier
 The string to append to the nick if it is already in use.
 @end defopt
@@ -1307,10 +1302,10 @@ settings (@pxref{Sample configuration via Customize}).
 
 (use-package erc
   :config
-  ;; Prefer SASL to NickServ, colorize nicknames, interpret mIRC colors,
-  ;; and list buffers and channel members in separate side panels.
+  ;; Prefer SASL to NickServ, colorize nicknames, and show side panels
+  ;; with joined channels and members
   (setopt erc-modules
-          (seq-union '(sasl nicks irccontrols bufbar nickbar scrolltobottom)
+          (seq-union '(sasl nicks bufbar nickbar scrolltobottom)
                      erc-modules))
 
   :custom
@@ -1318,6 +1313,8 @@ settings (@pxref{Sample configuration via Customize}).
   (erc-inhibit-multiline-input t)
   (erc-send-whitespace-lines t)
   (erc-ask-about-multiline-input t)
+  ;; Scroll all windows to prompt when submitting input.
+  (erc-scrolltobottom-all t)
 
   ;; Reconnect automatically using a fancy strategy.
   (erc-server-reconnect-function #'erc-server-delayed-check-reconnect)
@@ -1401,13 +1398,13 @@ As mentioned, Customize users can accomplish nearly all 
of the above
 via the Customize interface.  Start by running @kbd{M-x
 customize-group @key{RET} erc @key{RET}}, and search for ``Modules''
 with @kbd{C-s modules @key{RET}}.  Toggle open the flyout menu to
-reveal the full ``widget'' panel, a web-form-like interface for ``Erc
-Modules''.  Tick the boxes for @samp{bufbar}, @samp{irccontrols},
-@samp{nickbar}, @samp{nicks}, @samp{sasl}, and @samp{scrolltobottom}.
+reveal the full @dfn{widget} panel, a web-form-like interface for
+``Erc Modules''.  Tick the boxes for @samp{bufbar}, @samp{nickbar},
+@samp{nicks}, @samp{sasl}, and @samp{scrolltobottom}.
 
 Next, search for the phrases ``Erc Ask About Multiline Input'', ``Erc
-Inhibit Mulitline Input'', and ``Erc Send Whitespace Lines''.  These
-are the print names of three Boolean options that control how ERC
+Inhibit Multiline Input'', and ``Erc Send Whitespace Lines''.  These
+are the print names of three boolean options that control how ERC
 treats prompt input containing line breaks.  When visiting each
 option's section, twirl open its triangle icon to reveal its widget
 UI, and click its @samp{[Toggle]} button to set its value to @code{t}.
@@ -1453,12 +1450,19 @@ To make sure you've got this, try quickly customizing 
the option
 @code{erc-interactive-display}, which lives in the @samp{Erc Buffers}
 group (@kbd{M-x customize-group @key{RET} erc-buffers @key{RET}}).  As
 its doc string explains, the option controls where new buffers show up
-when you do @kbd{M-x erc-tls @key{RET}} or issue certain ``slash''
-commands, like @kbd{/JOIN #emacs-beginners @key{RET}}, at ERC's
+when you do @kbd{M-x erc-tls @key{RET}} or issue certain @dfn{slash
+commands}, like @kbd{/JOIN #emacs-beginners @key{RET}}, at ERC's
 prompt.  Change its value to the symbol @code{buffer} by choosing
 @samp{Use current window} (item @kbd{5}) from the option's
 @samp{[Value Menu]}.  Don't forget to save.
 
+If you need more practice, try enabling the boolean option
+@code{erc-scrolltobottom-all}, which lives in the @samp{Erc Display}
+group (@kbd{M-x customize-group @key{RET} erc-display @key{RET}}).
+When enabled, this option tells the @samp{scrolltobottom} module to
+adjust all ERC windows instead of just the one you're currently typing
+in.
+
 Now it's time to set some key bindings for @code{erc-mode-map}, a
 major-mode keymap active in all ERC buffers.  In general, it's best to
 do this part either entirely or in conjunction with some lisp code in
@@ -1535,8 +1539,8 @@ and save your changes.  Next, customize the related option
 @code{erc-track-priority-faces-only} to the @samp{[Value Menu]} choice
 @samp{all}.  Once again, save your changes.
 
-Let's say you'd like to enable a ``local module'' (ERC's version of a
-local minor mode) in a specific channel.  One way to do that is by
+Let's say you'd like to enable a @dfn{local module} (ERC's version of
+a local minor mode) in a specific channel.  One way to do that is by
 running some code to activate the module if the channel's name
 matches.  Try that now by customizing the option @code{erc-join-hook}.
 Add the following in the value field before saving your changes:
@@ -1548,7 +1552,7 @@ Add the following in the value field before saving your 
changes:
     (erc-keep-place-indicator-mode +1)))
 @end lisp
 
-Lastly, if you really want the two ``slash'' commands defined at the
+Lastly, if you really want the two @dfn{slash commands} defined at the
 end of the previous section, you can put them in any file listed in
 @code{erc-startup-file-list}, such as @file{~/.emacs.d/.ercrc.el}.
 Make sure to put @code{(require 'erc-track)} near the top of the file.
diff --git a/doc/misc/ert.texi b/doc/misc/ert.texi
index f4a072cf2bc..a0adb5fea2c 100644
--- a/doc/misc/ert.texi
+++ b/doc/misc/ert.texi
@@ -526,6 +526,7 @@ to find where a test was defined if the test was loaded 
from a file.
 * Tests and Their Environment:: Don't depend on customizations; no side 
effects.
 * Useful Techniques::           Some examples.
 * erts files::                  Files containing many buffer tests.
+* Syntax Highlighting Tests::   Tests for face assignment.
 @end menu
 
 
@@ -942,6 +943,102 @@ non-@code{nil} value, the test will be skipped.
 If you need to use the literal line single line @samp{=-=} in a test
 section, you can quote it with a @samp{\} character.
 
+@node Syntax Highlighting Tests
+@section Syntax Highlighting Tests
+
+Syntax highlighting is normally provided by the Font Lock minor mode
+that assigns face properties to parts of the buffer.  The
+@code{ert-font-lock} package makes it possible to introduce unit tests
+checking face assignment.  Test assertions are included in code-level
+comments directly and can be read either from inline strings or files.
+
+Test assertion parser extracts tests from comment-only lines.  Every
+comment assertion line starts either with a caret (@samp{^}) or an
+arrow (@samp{<-}).  A caret/arrow should be followed immediately by the
+name of a face to be checked.
+
+The test then checks if the first non-assertion column above the caret
+contains a face expected by the assertion:
+
+@example
+var variable = 11;
+//   ^ font-lock-variable-name-face
+//             ^ font-lock-literal-face
+//               ^ font-lock-punctuation-face
+// this is not an assertion, it's just a comment
+//   ^ font-lock-comment-face
+@end example
+
+The arrow means that the first non-empty column of the assertion line
+will be used for the check:
+
+@example
+var variable = 1;
+// <- font-lock-keyword-face
+  11;
+   // <- font-lock-literal-face
+@end example
+
+@findex ert-font-lock-test-string
+
+The @code{ert-font-lock-test-string} function extracts ERT assertions
+from an inline string.  The @code{javascript-mode} symbol below
+specifies the major mode used for comments and font locking:
+
+@lisp
+(ert-deftest test-font-lock-test-string--correct ()
+  (ert-font-lock-test-string
+   "
+var abc = function(d) @{
+// <- font-lock-keyword-face
+//   ^ font-lock-variable-name-face
+    //        ^ font-lock-keyword-face
+    //             ^ font-lock-variable-name-face
+@};
+"
+   'javascript-mode))
+@end lisp
+
+@findex ert-font-lock-test-file
+
+It is also possible to extract test assertions from a file:
+
+@lisp
+(ert-deftest test-font-lock-test-file--correct ()
+  (ert-font-lock-test-file
+   (ert-resource-file "correct.js")
+   'javascript-mode))
+@end lisp
+
+@findex ert-font-lock-deftest
+
+The @code{ert-font-lock-deftest} macro simplifies inline test
+definition:
+
+@lisp
+(ert-font-lock-deftest test-macro-test--inline
+    emacs-lisp-mode
+  "
+(defun fun ())
+;; ^ font-lock-keyword-face
+;;      ^ font-lock-function-name-face")
+@end lisp
+
+@findex ert-font-lock-deftest-file
+
+The @code{ert-font-lock-deftest-file} macro reads assertions from a
+file:
+
+@lisp
+(ert-font-lock-deftest-file test-macro-test--file
+    "Test reading correct assertions from a file"
+  javascript-mode
+  "correct.js")
+@end lisp
+
+The @code{ert-font-lock-deftest} and @code{ert-font-lock-deftest-file}
+macros accept the same keyword parameters as @code{ert-deftest} i.e.,
+@code{:tag} and @code{:expected-result}.
 
 @node How to Debug Tests
 @chapter How to Debug Tests
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index e8aa8cdc6a3..99a1491f1c3 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -1237,11 +1237,20 @@ command containing @code{foo}.  The n-th argument of 
the last command
 beginning with @code{foo} is accessible by @code{!foo:n}.
 
 @vindex eshell-history-file-name
-The history ring is loaded from a file at the start of every session,
-and written back to the file at the end of every session.  The file path
-is specified in @code{eshell-history-file-name}.  Unlike other shells,
-such as Bash, Eshell can not be configured to keep a history ring of a
-different size than that of the history file.
+@vindex eshell-history-append
+The history is loaded to the history ring from the file
+@code{eshell-history-file-name} at the start of every session, and
+saved to that file at the end of every session.  The default history
+saving behavior is to overwrite the history file with the whole
+history ring of the session.  If @code{eshell-history-append} is
+non-@code{nil}, the history will instead be saved by appending new
+entries from the session to the history file, which could prevent
+potential history loss with multiple Eshell sessions.  Unlike other
+shells, such as Bash, Eshell cannot currently be configured to control
+the size of the history file.  In particular, when
+@code{eshell-history-append} is non-@code{nil}, the size of the file
+will keep increasing, and the recommended way to truncate the file is
+to run the @samp{history -w} command in an Eshell session.
 
 Since the default buffer navigation and searching key-bindings are
 still present in the Eshell buffer, the commands for history
diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi
index 586e4b94ba1..fc41934ace4 100644
--- a/doc/misc/gnus.texi
+++ b/doc/misc/gnus.texi
@@ -5868,15 +5868,23 @@ original message but ignore the @code{Reply-To} field
 @findex gnus-summary-mail-forward
 @c @icon{gnus-summary-mail-forward}
 Forward the current article to some other person
-(@code{gnus-summary-mail-forward}).  If no prefix is given, the message
-is forwarded according to the value of (@code{message-forward-as-mime})
-and (@code{message-forward-show-mml}); if the prefix is 1, decode the
-message and forward directly inline; if the prefix is 2, forward message
-as an rfc822 @acronym{MIME} section; if the prefix is 3, decode message and
-forward as an rfc822 @acronym{MIME} section; if the prefix is 4, forward 
message
-directly inline; otherwise, the message is forwarded as no prefix given
-but use the flipped value of (@code{message-forward-as-mime}).  By
-default, the forwarded message is inlined into the mail.
+(@code{gnus-summary-mail-forward}).  If no prefix is given, the
+message is forwarded according to the value of
+(@code{message-forward-as-mime}) and
+(@code{message-forward-show-mml}); if the prefix is 1, decode the
+message and forward directly inline; if the prefix is 2, forward
+message as an rfc822 @acronym{MIME} section; if the prefix is 3,
+decode message and forward as an rfc822 @acronym{MIME} section; if the
+prefix is 4, forward message directly inline; otherwise, the message
+is forwarded as no prefix given but use the negated value of
+(@code{message-forward-as-mime}).  By default, the forwarded message
+is inlined into the mail.
+
+Which headers from the original message are included in the forwarded
+message is determined by options specific to @code{message-mode},
+@pxref{Forwarding,,, message}.  In addition, this command can be given
+the symbolic prefix @samp{a}, using @kbd{M-i a}, to include most original
+headers.
 
 @item S m
 @itemx m
@@ -6235,13 +6243,6 @@ Presumably, you want to use the demon for sending due 
delayed articles.
 Just don't forget to set that up :-)
 @end table
 
-When delaying an article with @kbd{C-c C-j}, Message mode will
-automatically add a @code{"Date"} header with the current time.  In
-many cases you probably want the @code{"Date"} header to reflect the
-time the message is sent instead.  To do this, you have to delete
-@code{Date} from @code{message-draft-headers}.
-
-
 @node Marking Articles
 @section Marking Articles
 @cindex article marking
diff --git a/doc/misc/modus-themes.org b/doc/misc/modus-themes.org
index 5a53426dfee..e109926cb72 100644
--- a/doc/misc/modus-themes.org
+++ b/doc/misc/modus-themes.org
@@ -90,7 +90,7 @@ The Modus themes consist of eight themes, divided into four 
subgroups.
   are variants of the two main themes.  They slightly tone down the
   intensity of the background and provide a bit more color variety.
   ~modus-operandi-tinted~ has a set of base tones that are shades of
-  light ochre (earthly colors), while ~modus-vivendi-tinted~ gives a
+  light ocher (earthly colors), while ~modus-vivendi-tinted~ gives a
   night sky impression.
 
 - Deuteranopia themes :: ~modus-operandi-deuteranopia~ and its
@@ -2518,7 +2518,7 @@ manual, here is what Protesilaos uses:
         ;; Add a nuanced background as well.
         (bg-prompt bg-magenta-nuanced)
         (fg-prompt magenta-cooler)
-        ;; Tweak some more constructs for stylistic constistency.
+        ;; Tweak some more constructs for stylistic consistency.
         (name blue-warmer)
         (identifier magenta-faint)
         (keybind magenta-cooler)
@@ -2717,7 +2717,7 @@ For a more elaborate design, it is better to inspect the 
source code of
 [[#h:51ba3547-b8c8-40d6-ba5a-4586477fd4ae][Use theme colors in code with 
modus-themes-with-colors]].
 
 #+findex: modus-themes-get-color-value
-The fuction ~modus-themes-get-color-value~ can be called from Lisp to
+The function ~modus-themes-get-color-value~ can be called from Lisp to
 return the value of a color from the active Modus theme palette.  It
 takea a =COLOR= argument and an optional =OVERRIDES=.
 
@@ -2886,7 +2886,7 @@ above:
 The reason we no longer provide this option is because it depends on a
 non-~nil~ value for ~x-underline-at-descent-line~.  That variable
 affects ALL underlines, including those of links.  The effect is
-intrusive and looks awkard in prose.
+intrusive and looks awkward in prose.
 
 As such, the Modus themes no longer provide that option but instead
 offer this piece of documentation to make the user fully aware of the
@@ -3229,7 +3229,7 @@ specification of that variable looks like this:
 
 With the exception of ~org-verbatim~ and ~org-code~ faces, everything else
 uses the corresponding type of emphasis: a bold typographic weight, or
-italicised, underlined, and struck through text.
+italicized, underlined, and struck through text.
 
 The best way for users to add some extra attributes, such as a
 foreground color, is to define their own faces and assign them to the
@@ -4396,7 +4396,7 @@ advanced customization options of the themes.
 [[#h:f4651d55-8c07-46aa-b52b-bed1e53463bb][Advanced customization]].
 
 In the following example, we are assuming that the user wants to (i)
-re-use color variables provided by the themes, (ii) be able to retain
+reuse color variables provided by the themes, (ii) be able to retain
 their tweaks while switching between ~modus-operandi~ and ~modus-vivendi~,
 and (iii) have the option to highlight either the foreground of the
 parentheses or the background as well.
@@ -4416,7 +4416,7 @@ Then we can update our preference with this:
 (setq my-highlight-parentheses-use-background nil)
 #+end_src
 
-To re-use colors from the themes, we must wrap our code in the
+To reuse colors from the themes, we must wrap our code in the
 ~modus-themes-with-colors~ macro.  Our implementation must interface with
 the variables ~highlight-parentheses-background-colors~ and/or
 ~highlight-parentheses-colors~.
@@ -5026,7 +5026,7 @@ more effective than trying to do the same with either red 
or blue (the
 latter is the least effective in that regard).
 
 When we need to work with several colors, it is always better to have
-sufficient manoeuvring space, especially since we cannot pick arbitrary
+sufficient maneuvering space, especially since we cannot pick arbitrary
 colors but only those that satisfy the accessibility objectives of the
 themes.
 
@@ -5080,7 +5080,7 @@ each of the three channels of light (red, green, blue).  
For example:
 : xrandr --output LVDS1 --brightness 1.0 --gamma 0.76:0.75:0.68
 
 Typography is another variable.  Some font families are blurry at small
-point sizes.  Others may have a regular weight that is lighter (thiner)
+point sizes.  Others may have a regular weight that is lighter (thinner)
 than that of their peers which may, under certain circumstances, cause a
 halo effect around each glyph.
 
@@ -5132,7 +5132,7 @@ it is already understood that one must follow the 
indicator or headline
 to view its contents and (ii) underlining everything would make the
 interface virtually unusable.
 
-Again, one must exercise judgement in order to avoid discrimination,
+Again, one must exercise judgment in order to avoid discrimination,
 where "discrimination" refers to:
 
 + The treatment of substantially different magnitudes as if they were of
@@ -5206,7 +5206,7 @@ the themes, which is partially fleshed out in this manual.
 
 With regard to the artistic aspect (where "art" qua skill may amount to
 an imprecise science), there is no hard-and-fast rule in effect as it
-requires one to exercize discretion and make decisions based on
+requires one to exercise discretion and make decisions based on
 context-dependent information or constraints.  As is true with most
 things in life, when in doubt, do not cling on to the letter of the law
 but try to understand its spirit.
diff --git a/doc/misc/tramp.texi b/doc/misc/tramp.texi
index c21426a32f7..7a95a6dbc98 100644
--- a/doc/misc/tramp.texi
+++ b/doc/misc/tramp.texi
@@ -3671,7 +3671,7 @@ ssh@value{postfixhop}you@@remotehost@value{postfix}/path 
@key{RET}}
 Each involved method must be an inline method (@pxref{Inline methods}).
 
 @value{tramp} adds the ad-hoc definitions on the fly to
-@code{tramp-default-proxies-alist} and is available for re-use during
+@code{tramp-default-proxies-alist} and is available for reuse during
 that Emacs session.  Subsequent @value{tramp} connections to the same
 remote host can then use the shortcut form:
 @samp{@trampfn{ssh,you@@remotehost,/path}}.
@@ -4201,7 +4201,7 @@ To open @command{powershell} as a remote shell, use this:
 
 @subsection Remote process connection type
 @vindex process-connection-type
-@cindex tramp-process-connection-type
+@vindex tramp-process-connection-type
 
 Asynchronous processes behave differently based on whether they use a
 pseudo tty or not.  This is controlled by the variable
@@ -4338,7 +4338,7 @@ called @code{tramp-connection-local-*-ps-profile} and
 @end group
 @end lisp
 
-@cindex proced
+@cindex @code{proced}
 @vindex proced-show-remote-processes
 If you want to see a listing of remote system processes when calling
 @code{proced}, set user option @code{proced-show-remote-processes} to
@@ -5322,17 +5322,39 @@ customization is explained in user option
 @item
 Remote host does not understand default options for directory listing
 
-Emacs computes the @command{dired} options based on the local host but
-if the remote host cannot understand the same @command{ls} command,
-then set them with a hook as follows:
+@vindex dired-listing-switches
+Emacs computes the @command{dired} options based on the local host.
+Since @w{Emacs 30}, these options can be set connection-local.
+@ifinfo
+@xref{Connection Variables, , , emacs}.
+@end ifinfo
+
+@lisp
+@group
+(connection-local-set-profile-variables
+  'my-dired-profile
+  '((dired-listing-switches . "-ahl")))
+@end group
+
+@group
+(connection-local-set-profiles
+ '(:application tramp :machine "remotehost")
+ 'my-dired-profile)
+@end group
+@end lisp
+
+@vindex dired-actual-switches
+In older Emacsen, you can set the @command{dired} options with a hook
+as follows:
 
 @lisp
 @group
 (add-hook
  'dired-before-readin-hook
  (lambda ()
-   (when (file-remote-p default-directory)
-     (setq dired-actual-switches "-al"))))
+   (when (string-equal
+           (file-remote-p default-directory 'host) "remotehost")
+     (setq dired-actual-switches "-ahl"))))
 @end group
 @end lisp
 
diff --git a/doc/misc/transient.texi b/doc/misc/transient.texi
index e06f7759d1b..cba434d072e 100644
--- a/doc/misc/transient.texi
+++ b/doc/misc/transient.texi
@@ -31,7 +31,7 @@ General Public License for more details.
 @finalout
 @titlepage
 @title Transient User and Developer Manual
-@subtitle for version 0.4.3
+@subtitle for version 0.5.2
 @author Jonas Bernoulli
 @page
 @vskip 0pt plus 1filll
@@ -44,37 +44,16 @@ General Public License for more details.
 @node Top
 @top Transient User and Developer Manual
 
-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
-commands (a prefix and a suffix) we prefer to call it just a
-``transient''.
-
-When the user calls a transient prefix command, a transient
-(temporary) keymap is activated, which binds the transient's infix
-and suffix commands, and functions that control the transient state
-are added to @code{pre-command-hook} and @code{post-command-hook}.  The 
available
-suffix and infix commands and their state are shown in a popup buffer
-until the transient is exited by invoking a suffix command.
-
-Calling an infix command causes its value to be changed, possibly by
-reading a new value in the minibuffer.
+Transient is the library used to implement the keyboard-driven ``menus''
+in Magit.  It is distributed as a separate package, so that it can be
+used to implement similar menus in other packages.
 
-Calling a suffix command usually causes the transient to be exited
-but suffix commands can also be configured to not exit the transient.
-
-@quotation
-The second part of this manual, which describes how to modify existing
-transients and create new transients from scratch, can be hard to
-digest if you are just getting started.  A useful resource to get over
-that hurdle is Psionic K's interactive tutorial, available at
-@uref{https://github.com/positron-solutions/transient-showcase}.
-
-@end quotation
+This manual can be bit hard to digest when getting started.  A useful
+resource to get over that hurdle is Psionic K's interactive tutorial,
+available at @uref{https://github.com/positron-solutions/transient-showcase}.
 
 @noindent
-This manual is for Transient version 0.4.3.
+This manual is for Transient version 0.5.2.
 
 @insertcopying
 @end ifnottex
@@ -85,7 +64,6 @@ This manual is for Transient version 0.4.3.
 * Modifying Existing Transients::
 * Defining New Commands::
 * Classes and Methods::
-* Related Abstractions and Packages::
 * FAQ::
 * Keystroke Index::
 * Command and Function Index::
@@ -110,6 +88,7 @@ Usage
 
 Defining New Commands
 
+* Technical Introduction::
 * Defining Transients::
 * Binding Suffix and Infix Commands::
 * Defining Suffix and Infix Commands::
@@ -139,153 +118,87 @@ Suffix Methods
 * Suffix Format Methods::
 
 
-Related Abstractions and Packages
-
-* Comparison With Prefix Keys and Prefix Arguments::
-* Comparison With Other Packages::
-
 @end detailmenu
 @end menu
 
 @node Introduction
 @chapter Introduction
 
-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
-commands (a prefix and a suffix) we prefer to call it just a
-``transient''.
-
-@cindex transient prefix command
-@quotation
-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
-we sometimes use the terms @dfn{transient prefix command} for our kind and
-``regular prefix command'' for Emacs' kind.
-
-@end quotation
+Transient is the library used to implement the keyboard-driven @dfn{menus}
+in Magit.  It is distributed as a separate package, so that it can be
+used to implement similar menus in other packages.
 
-When the user calls a transient prefix command, a transient
-(temporary) keymap is activated, which binds the transient's infix and
-suffix commands, and functions that control the transient state are
-added to @code{pre-command-hook} and @code{post-command-hook}.  The available 
suffix
-and infix commands and their state are shown in a popup buffer until
-the transient state is exited by invoking a suffix command.
-
-Calling an infix command causes its value to be changed.  How that is
-done depends on the type of the infix command.  The simplest case is
-an infix command that represents a command-line argument that does not
-take a value.  Invoking such an infix command causes the switch to be
-toggled on or off.  More complex infix commands may read a value from
-the user, using the minibuffer.
-
-Calling a suffix command usually causes the transient to be exited;
-the transient keymaps and hook functions are removed, the popup buffer
-no longer shows information about the (no longer bound) suffix
-commands, the values of some public global variables are set, while
-some internal global variables are unset, and finally the command is
-actually called.  Suffix commands can also be configured to not exit
-the transient.
-
-A suffix command can, but does not have to, use the infix arguments in
-much the same way any command can choose to use or ignore the prefix
-arguments.  For a suffix command that was invoked from a transient, the
-variable @code{transient-current-suffixes} and the function 
@code{transient-args}
-serve about the same purpose as the variables @code{prefix-arg} and
-@code{current-prefix-arg} do for any command that was called after the prefix
-arguments have been set using a command such as @code{universal-argument}.
-
-The information shown in the popup buffer while a transient is active
-looks a bit like this:
-
-@example
-,-----------------------------------------
-|Arguments
-| -f Force (--force)
-| -a Annotate (--annotate)
-|
-|Create
-| t tag
-| r release
-`-----------------------------------------
-@end example
-
-@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
-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.
-
-@end quotation
-
-@cindex command dispatchers
-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
-prefix key or command.  Magit's @code{magit-dispatch} (on @kbd{C-x M-g}) 
command is
-an example of using Transient to merely implement a command
-dispatcher.
-
-In addition to that, Transient also allows users to interactively pass
-arguments to commands.  These arguments can be much more complex than
-what is reasonable when using prefix arguments.  There is a limit to
-how many aspects of a command can be controlled using prefix
-arguments.  Furthermore, what a certain prefix argument means for
-different commands can be completely different, and users have to read
-documentation to learn and then commit to memory what a certain prefix
-argument means to a certain command.
-
-Transient suffix commands, on the other hand, can accept dozens of
-different arguments without the user having to remember anything.
-When using Transient, one can call a command with arguments that are
-just as complex as when calling the same function non-interactively
-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
-these arguments, and previously it was invoked using those other
-arguments''), but also remembers the values of individual arguments
-independently.  See @xref{Using History}.
+This manual can be bit hard to digest when getting started.  A useful
+resource to get over that hurdle is Psionic K's interactive tutorial,
+available at @uref{https://github.com/positron-solutions/transient-showcase}.
 
-After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to
-show the documentation for the infix or suffix command that @kbd{@var{KEY}} is
-bound to (see @ref{Getting Help for Suffix Commands}), and infixes and
-suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}. Infixes
-and suffixes that are disabled by default can be enabled the same way.
-@xref{Enabling and Disabling Suffixes}.
+@anchor{Some things that Transient can do}
+@heading Some things that Transient can do
 
-Transient ships with support for a few different types of specialized
-infix commands.  A command that sets a command line option, for example,
-has different needs than a command that merely toggles a boolean flag.
-Additionally, Transient provides abstractions for defining new types,
-which the author of Transient did not anticipate (or didn't get around
-to implementing yet).
+@itemize
+@item
+Display current state of arguments
+@item
+Display and manage lifecycle of modal bindings
+@item
+Contextual user interface
+@item
+Flow control for wizard-like composition of interactive forms
+@item
+History & persistence
+@item
+Rendering arguments for controlling CLI programs
+@end itemize
 
-Note that suffix commands also support regular prefix arguments.  A
-suffix command may even be called with both infix and prefix arguments
-at the same time.  If you invoke a command as a suffix of a transient
-prefix command, but also want to pass prefix arguments to it, then
-first invoke the prefix command, and only after doing that invoke the
-prefix arguments, before finally invoking the suffix command.  If you
-instead began by providing the prefix arguments, then those would
-apply to the prefix command, not the suffix command.  Likewise, if you
-want to change infix arguments before invoking a suffix command with
-prefix arguments, then change the infix arguments before invoking the
-prefix arguments.  In other words, regular prefix arguments always
-apply to the next command, and since transient prefix, infix and
-suffix commands are just regular commands, the same applies to them.
-(Regular prefix keys behave differently because they are not commands
-at all, instead they are just incomplete key sequences, and those
-cannot be interrupted with prefix commands.)
+@anchor{Complexity in CLI programs}
+@heading Complexity in CLI programs
+
+Complexity tends to grow with time.  How do you manage the complexity
+of commands?  Consider the humble shell command @samp{ls}.  It now has over
+@emph{fifty} command line options.  Some of these are boolean flags (@samp{ls 
-l}).
+Some take arguments (@samp{ls --sort=s}).  Some have no effect unless paired
+with other flags (@samp{ls -lh}).  Some are mutually exclusive.  Some shell
+commands even have so many options that they introduce @emph{subcommands}
+(@samp{git branch}, @samp{git commit}), each with their own rich set of options
+(@samp{git branch -f}).
+
+@anchor{Using Transient for composing interactive commands}
+@heading Using Transient for composing interactive commands
+
+What about Emacs commands used interactively? How do these handle
+options?  One solution is to make many versions of the same command,
+so you don't need to! Consider: @samp{delete-other-windows} vs.
+@samp{delete-other-windows-vertically} (among many similar examples).
+
+Some Emacs commands will simply prompt you for the next "argument"
+(@samp{M-x switch-to-buffer}).  Another common solution is to use prefix
+arguments which usually start with @samp{C-u}.  Sometimes these are sensibly
+numerical in nature (@samp{C-u 4 M-x forward-paragraph} to move forward 4
+paragraphs).  But sometimes they function instead as boolean
+"switches" (@samp{C-u C-SPACE} to jump to the last mark instead of just
+setting it, @samp{C-u C-u C-SPACE} to unconditionally set the mark).  Since
+there aren't many standards for the use of prefix options, you have to
+read the command's documentation to find out what the possibilities
+are.
+
+But when an Emacs command grows to have a truly large set of options
+and arguments, with dependencies between them, lots of option values,
+etc., these simple approaches just don't scale.  Transient is designed
+to solve this issue.  Think of it as the humble prefix argument @samp{C-u},
+@emph{raised to the power of 10}.  Like @samp{C-u}, it is key driven.  Like the
+shell, it supports boolean "flag" options, options that take
+arguments, and even "sub-commands", with their own options.  But
+instead of searching through a man page or command documentation,
+well-designed transients @emph{guide} their users to the relevant set of
+options (and even their possible values!) directly, taking into
+account any important pre-existing Emacs settings.  And while for
+shell commands like @samp{ls}, there is only one way to "execute" (hit
+@samp{Return}!), transients can "execute" using multiple different keys tied
+to one of many self-documenting @emph{actions} (imagine having 5 different
+colored return keys on your keyboard!).  Transients make navigating
+and setting large, complex groups of command options and arguments
+easy.  Fun even.  Once you've tried it, it's hard to go back to the
+@samp{C-u what can I do here again?} way.
 
 @node Usage
 @chapter Usage
@@ -366,7 +279,7 @@ it returns to the previous transient, if any.
 
 Transient's predecessor bound @kbd{q} instead of @kbd{C-g} to the quit command.
 To learn how to get that binding back see @code{transient-bind-q-to-quit}'s
-doc string.
+documentation string.
 
 @table @asis
 @item @kbd{C-q} (@code{transient-quit-all})
@@ -562,8 +475,8 @@ What sort of documentation is shown depends on how the 
transient was
 defined.  For infix commands that represent command-line arguments
 this ideally shows the appropriate manpage.  @code{transient-help} then tries
 to jump to the correct location within that.  Info manuals are also
-supported.  The fallback is to show the command's doc string, for
-non-infix suffixes this is usually appropriate.
+supported.  The fallback is to show the command's documentation
+string, for non-infix suffixes this is usually appropriate.
 
 @node Enabling and Disabling Suffixes
 @section Enabling and Disabling Suffixes
@@ -637,6 +550,13 @@ not.  The predicates also apply in edit mode.
 
 Therefore, to control which suffixes are available given a certain
 state, you have to make sure that that state is currently active.
+
+@item @kbd{C-x a} (@code{transient-toggle-level-limit})
+@kindex C-x a
+@findex transient-toggle-level-limit
+This command toggle whether suffixes that are on levels lower than
+the level specified by @code{transient-default-level} are temporarily
+available anyway.
 @end table
 
 @node Other Commands
@@ -782,27 +702,31 @@ If @code{nil}, then the buffer has no mode-line.  If the 
buffer is not
 displayed right above the echo area, then this probably is not a
 good value.
 
-If @code{line} (the default), then the buffer also has no mode-line, but a
-thin line is drawn instead, using the background color of the face
-@code{transient-separator}.  Text-mode frames cannot display thin lines,
-and therefore fall back to treating @code{line} like @code{nil}.
+If @code{line} (the default) or a natural number, then the buffer
+has no mode-line, but a line is drawn is drawn in its place.
+If a number is used, that specifies the thickness of the line.
+On termcap frames we cannot draw lines, so there @code{line} and
+numbers are synonyms for @code{nil}.
+
+The color of the line is used to indicate if non-suffixes are
+allowed and whether they exit the transient.  The foreground
+color of @code{transient-key-noop} (if non-suffix are disallowed),
+@code{transient-key-stay} (if allowed and transient stays active), or
+@code{transient-key-exit} (if allowed and they exit the transient) is
+used to draw the line.
 
 Otherwise this can be any mode-line format.  @xref{Mode Line
 Format,,,elisp,}, for details.
 @end defopt
 
 @defopt transient-semantic-coloring
-This option controls whether prefixes and suffixes are colored in
-a Hydra-like fashion.
+This option controls whether colors are used to indicate the
+transient behavior of commands.
 
 If non-@code{nil}, then the key binding of each suffix is colorized to
 indicate whether it exits the transient state or not.  The color of
 the prefix is indicated using the line that is drawn when the value
 of @code{transient-mode-line-format} is @code{line}.
-
-For more information about how Hydra uses colors see
-@uref{https://github.com/abo-abo/hydra#color} and
-@uref{https://oremacs.com/2015/02/19/hydra-colors-reloaded}.
 @end defopt
 
 @defopt transient-highlight-mismatched-keys
@@ -1015,6 +939,7 @@ signal an error.
 @chapter Defining New Commands
 
 @menu
+* Technical Introduction::
 * Defining Transients::
 * Binding Suffix and Infix Commands::
 * Defining Suffix and Infix Commands::
@@ -1022,6 +947,106 @@ signal an error.
 * Transient State::
 @end menu
 
+@node Technical Introduction
+@section Technical Introduction
+
+Taking inspiration from prefix keys and prefix arguments, Transient
+implements a similar abstraction involving a prefix command, infix
+arguments and suffix commands.
+
+When the user calls a transient prefix command, a transient
+(temporary) keymap is activated, which binds the transient's infix and
+suffix commands, and functions that control the transient state are
+added to @code{pre-command-hook} and @code{post-command-hook}.  The available 
suffix
+and infix commands and their state are shown in a popup buffer until
+the transient state is exited by invoking a suffix command.
+
+Calling an infix command causes its value to be changed.  How that is
+done depends on the type of the infix command.  The simplest case is
+an infix command that represents a command-line argument that does not
+take a value.  Invoking such an infix command causes the switch to be
+toggled on or off.  More complex infix commands may read a value from
+the user, using the minibuffer.
+
+Calling a suffix command usually causes the transient to be exited;
+the transient keymaps and hook functions are removed, the popup buffer
+no longer shows information about the (no longer bound) suffix
+commands, the values of some public global variables are set, while
+some internal global variables are unset, and finally the command is
+actually called.  Suffix commands can also be configured to not exit
+the transient.
+
+A suffix command can, but does not have to, use the infix arguments in
+much the same way any command can choose to use or ignore the prefix
+arguments.  For a suffix command that was invoked from a transient, the
+variable @code{transient-current-suffixes} and the function 
@code{transient-args}
+serve about the same purpose as the variables @code{prefix-arg} and
+@code{current-prefix-arg} do for any command that was called after the prefix
+arguments have been set using a command such as @code{universal-argument}.
+
+@cindex command dispatchers
+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, which can be thought of as a ``menus''.  That is
+useful by itself because it frees the user from having to remember all
+the keys that are valid after a certain prefix key or command.
+Magit's @code{magit-dispatch} (on @kbd{C-x M-g}) command is an example of using
+Transient to merely implement a command dispatcher.
+
+In addition to that, Transient also allows users to interactively pass
+arguments to commands.  These arguments can be much more complex than
+what is reasonable when using prefix arguments.  There is a limit to
+how many aspects of a command can be controlled using prefix
+arguments.  Furthermore, what a certain prefix argument means for
+different commands can be completely different, and users have to read
+documentation to learn and then commit to memory what a certain prefix
+argument means to a certain command.
+
+Transient suffix commands, on the other hand, can accept dozens of
+different arguments without the user having to remember anything.
+When using Transient, one can call a command with arguments that are
+just as complex as when calling the same function non-interactively
+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
+these arguments, and previously it was invoked using those other
+arguments''), but also remembers the values of individual arguments
+independently.  See @ref{Using History}.
+
+After a transient prefix command is invoked, @kbd{C-h @var{KEY}} can be used to
+show the documentation for the infix or suffix command that @kbd{@var{KEY}} is
+bound to (see @ref{Getting Help for Suffix Commands}), and infixes and
+suffixes can be removed from the transient using @kbd{C-x l @var{KEY}}. Infixes
+and suffixes that are disabled by default can be enabled the same way.
+See @ref{Enabling and Disabling Suffixes}.
+
+Transient ships with support for a few different types of specialized
+infix commands.  A command that sets a command line option, for example,
+has different needs than a command that merely toggles a boolean flag.
+Additionally, Transient provides abstractions for defining new types,
+which the author of Transient did not anticipate (or didn't get around
+to implementing yet).
+
+Note that suffix commands also support regular prefix arguments.  A
+suffix command may even be called with both infix and prefix arguments
+at the same time.  If you invoke a command as a suffix of a transient
+prefix command, but also want to pass prefix arguments to it, then
+first invoke the prefix command, and only after doing that invoke the
+prefix arguments, before finally invoking the suffix command.  If you
+instead began by providing the prefix arguments, then those would
+apply to the prefix command, not the suffix command.  Likewise, if you
+want to change infix arguments before invoking a suffix command with
+prefix arguments, then change the infix arguments before invoking the
+prefix arguments.  In other words, regular prefix arguments always
+apply to the next command, and since transient prefix, infix and
+suffix commands are just regular commands, the same applies to them.
+(Regular prefix keys behave differently because they are not commands
+at all, instead they are just incomplete key sequences, and those
+cannot be interrupted with prefix commands.)
+
 @node Defining Transients
 @section Defining Transients
 
@@ -1087,10 +1112,9 @@ Transients}) and adds the transient's infix and suffix 
bindings, as
 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
-the specifications used in @code{transient-define-prefix}.
+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 the specifications used in
+@code{transient-define-prefix}.
 
 @menu
 * Group Specifications::
@@ -1251,10 +1275,10 @@ the object's values just for the binding inside this 
transient.
 
 @item
 @var{DESCRIPTION} is the description, either a string or a function that
-returns a string.  The function should be a lambda expression to
-avoid ambiguity.  In some cases a symbol that is bound as a function
-would also work but to be safe you should use @code{:description} in that
-case.
+takes zero or one arguments (the suffix object) and returns a string.
+The function should be a lambda expression to avoid ambiguity.  In
+some cases a symbol that is bound as a function would also work but
+to be safe you should use @code{:description} in that case.
 @end itemize
 
 The next element is either a command or an argument.  This is the only
@@ -1475,63 +1499,55 @@ transient keymap is disallowed and trying to do so 
results in a
 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''
-function.  Whether non-suffix commands are allowed to be called is
-configurable per transient.
+The behavior can be changed for all suffixes of a particular prefix
+and/or for individual suffixes.  The values should nearly always be
+booleans, but certain functions, called ``pre-commands'', can also be
+used.  These functions are named @code{transient--do-VERB}, and the symbol
+@code{VERB} can be used as a shorthand.
 
-@itemize
-@item
-The transient-ness of suffix commands (including infix commands) is
-controlled by the value of their @code{transient} slot, which can be set
-either when defining the command or when adding a binding to a
-transient while defining the respective transient prefix command.
+A boolean is interpreted as answering the question "does the
+transient stay active, when this command is invoked?"  @code{t} means that
+the transient stays active, while @code{nil} means that invoking the command
+exits the transient.
 
-Valid values are booleans and the pre-commands described below.
+Note that when the suffix is a ``sub-prefix'', invoking that command
+always activates that sub-prefix, causing the outer prefix to no
+longer be active and displayed.  Here @code{t} means that when you exit the
+inner prefix, then the outer prefix becomes active again, while @code{nil}
+means that all outer prefixes are exited at once.
 
 @itemize
 @item
-@code{t} is equivalent to @code{transient--do-stay}.
-@item
-@code{nil} is equivalent to @code{transient--do-exit}.
-@item
-If @code{transient} is unbound (and that is actually the default for
-non-infix suffixes) then the value of the prefix's
-@code{transient-suffix} slot is used instead.  The default value of that
-slot is @code{nil}, so the suffix's @code{transient} slot being unbound is
-essentially equivalent to it being @code{nil}.
-@end itemize
+The behavior for non-suffixes can be set for a particular prefix,
+by the prefix's @code{transient-non-suffix} slot to a boolean, a suitable
+pre-command function, or a shorthand for such a function.  See
+@ref{Pre-commands for Non-Suffixes}.
 
 @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
-cases this may not be desirable, and that makes the following
-complication necessary:
+The common behavior for the suffixes of a particular prefix can be
+set using the prefix's @code{transient-suffixes} slot.
 
-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
-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
-slot to be explicitly set to that value.
+The value specified in this slot does @strong{not} affect infixes.  Because
+it affects both regular suffixes as well as sub-prefixes, which
+have different needs, it is best to avoid explicitly specifying a
+function.
 
 @item
-The transient-ness of certain built-in suffix commands is specified
-using @code{transient-predicate-map}.  This is a special keymap, which
-binds commands to pre-commands (as opposed to keys to commands) and
-takes precedence over the @code{transient} slot.
+The behavior of an individual suffix can be changed using its
+@code{transient} slot.  While it is usually best to use a boolean, for this
+slot it can occasionally make sense to specify a function explicitly.
+
+Note that this slot can be set when defining a suffix command using
+@code{transient-define-suffix} and/or in the definition of the prefix.  If
+set in both places, then the latter takes precedence, as usual.
 @end itemize
 
-The available pre-command functions are documented below.  They are
-called by @code{transient--pre-command}, a function on @code{pre-command-hook} 
and
-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'').
+The available pre-command functions are documented in the following
+sub-sections.  They are called by @code{transient--pre-command}, a function
+on @code{pre-command-hook}, and 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'').
 
 Additionally, these functions may change the value of @code{this-command}
 (which explains why they have to be called using @code{pre-command-hook}),
@@ -1539,11 +1555,39 @@ call @code{transient-export}, 
@code{transient--stack-zap} or @code{transient--st
 and set the values of @code{transient--exitp}, @code{transient--helpp} or
 @code{transient--editp}.
 
+For completeness sake, some notes about complications:
+
+@itemize
+@item
+The transient-ness of certain built-in suffix commands is specified
+using @code{transient-predicate-map}.  This is a special keymap, which
+binds commands to pre-commands (as opposed to keys to commands) and
+takes precedence over the prefix's @code{transient-suffix} slot, but not
+the suffix's @code{transient} slot.
+
+@item
+While a sub-prefix is active we nearly always want @kbd{C-g} to take the
+user back to the ``super-prefix'', even when the other suffixes don't
+do that.  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 @code{nil} and the slot being unbound
+are treated as 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 slot to
+be explicitly set to that value.
+@end itemize
+
 @anchor{Pre-commands for Infixes}
 @subheading Pre-commands for Infixes
 
 The default for infixes is @code{transient--do-stay}.  This is also the only
-function that makes sense for infixes.
+function that makes sense for infixes, which is why this predicate is
+used even if the value of the prefix's @code{transient-suffix} slot is 
@code{t}.  In
+extremely rare cases, one might want to use something else, which can
+be done by setting the infix's @code{transient} slot directly.
 
 @defun transient--do-stay
 Call the command without exporting variables and stay transient.
@@ -1554,23 +1598,16 @@ Call the command without exporting variables and stay 
transient.
 
 By default, invoking a suffix causes the transient to be exited.
 
-If you want a different default behavior for a certain transient
-prefix command, then set its @code{:transient-suffix} slot.  The value can be
-a boolean, answering the question "does the transient stay active,
-when a suffix command is invoked?"  @code{t} means that the transient stays
-active, while @code{nil} means that invoking a suffix exits the transient.
-In either case, the exact behavior depends on whether the suffix is
-itself a prefix (i.e., a sub-prefix), an infix or a regular suffix.
-
 The behavior for an individual suffix command can be changed by
-setting its @code{transient} slot to one of the following pre-commands.
+setting its @code{transient} slot to a boolean (which is highly recommended),
+or to one of the following pre-commands.
 
 @defun transient--do-exit
 Call the command after exporting variables and exit the transient.
 @end defun
 
 @defun transient--do-return
-Call the command after exporting variables and return to parent
+Call the command after exporting variables and return to the parent
 prefix.  If there is no parent prefix, then call @code{transient--do-exit}.
 @end defun
 
@@ -1578,9 +1615,10 @@ prefix.  If there is no parent prefix, then call 
@code{transient--do-exit}.
 Call the command after exporting variables and stay transient.
 @end defun
 
-The following pre-commands are suitable for sub-prefixes.  Only the
-first should ever explicitly be set as the value of the @code{transient}
-slot.
+The following pre-commands are only suitable for sub-prefixes.  It is
+not necessary to explicitly use these predicates because the correct
+predicate is automatically picked based on the value of the @code{transient}
+slot for the sub-prefix itself.
 
 @defun transient--do-recurse
 Call the transient prefix command, preparing for return to active
@@ -1588,15 +1626,25 @@ transient.
 
 Whether we actually return to the parent transient is ultimately
 under the control of each invoked suffix.  The difference between
-this pre-command and @code{transient--do-replace} is that it changes the
-value of the @code{transient-suffix} slot to @code{transient--do-return}.
+this pre-command and @code{transient--do-stack} is that it changes the
+value of the @code{transient-suffix} slot to @code{t}.
 
 If there is no parent transient, then only call this command and
 skip the second step.
 @end defun
 
+@defun transient--do-stack
+Call the transient prefix command, stacking the active transient.
+Push the active transient to the transient stack.
+
+Unless @code{transient--do-recurse} is explicitly used, this pre-command
+is automatically used for suffixes that are prefixes themselves,
+i.e., for sub-prefixes.
+@end defun
+
 @defun transient--do-replace
 Call the transient prefix command, replacing the active transient.
+Do not push the active transient to the transient stack.
 
 Unless @code{transient--do-recurse} is explicitly used, this pre-command
 is automatically used for suffixes that are prefixes themselves,
@@ -1618,17 +1666,17 @@ By default, non-suffixes (commands that are bound in 
other keymaps
 beside the transient keymap) cannot be invoked.  Trying to invoke
 such a command results in a warning and the transient stays active.
 
-If you want a different behavior, then set the @code{:transient-non-suffix}
-slot of the transient prefix command.  The value can be a boolean,
-answering the question, "is it allowed to invoke non-suffix commands?"
+If you want a different behavior, then set the @code{transient-non-suffix}
+slot of the transient prefix command.  The value should be a boolean,
+answering the question, "is it allowed to invoke non-suffix commands?,
+a pre-command function, or a shorthand for such a function.
 
-If the value is @code{t} or @code{transient--do-stay}, then non-suffixes can be
-invoked, when it is @code{nil} or @code{transient--do-warn} (the default) then 
they
-cannot be invoked.
+If the value is @code{t}, then non-suffixes can be invoked, when it is 
@code{nil}
+(the default) then they cannot be invoked.
 
-The only other recommended value is @code{transient--do-leave}.  If that is
-used, then non-suffixes can be invoked, but if one is invoked, then
-that exits the transient.
+The only other recommended value is @code{leave}.  If that is used, then
+non-suffixes can be invoked, but if one is invoked, then that exits
+the transient.
 
 @defun transient--do-warn
 Call @code{transient-undefined} and stay transient.
@@ -1870,6 +1918,24 @@ indicates that all remaining arguments are files.
 @item
 Classes used for infix commands that represent variables should
 derived from the abstract @code{transient-variable} class.
+
+@item
+The @code{transient-information} class is special in that suffixes that use
+this class are not associated with a command and thus also not with
+any key binding.  Such suffixes are only used to display arbitrary
+information, and that anywhere a suffix can appear.  Display-only
+suffix specifications take this form:
+
+@lisp
+([LEVEL] :info DESCRIPTION [KEYWORD VALUE]...)
+@end lisp
+
+The @code{:info} keyword argument replaces the @code{:description} keyword 
used for
+other suffix classes.  Other keyword arguments that you might want to
+set, include @code{:face}, predicate keywords (such as @code{:if}), and 
@code{:format}.
+By default the value of @code{:format} includes @code{%k}, which for this 
class is
+replaced with the empty string or spaces, if keys are being padded in
+the containing group.
 @end itemize
 
 Magit defines additional classes, which can serve as examples for the
@@ -1990,12 +2056,13 @@ Show help for the prefix, infix or suffix command 
represented by
 
 For prefixes, show the info manual, if that is specified using the
 @code{info-manual} slot.  Otherwise, show the manpage if that is specified
-using the @code{man-page} slot.  Otherwise, show the command's doc string.
+using the @code{man-page} slot.  Otherwise, show the command's
+documentation string.
 
-For suffixes, show the command's doc string.
+For suffixes, show the command's documentation string.
 
 For infixes, show the manpage if that is specified.  Otherwise show
-the command's doc string.
+the command's documentation string.
 @end defun
 
 @node Prefix Slots
@@ -2019,11 +2086,24 @@ determining whether the currently active transient 
prefix command
 remains active/transient when a suffix or arbitrary non-suffix
 command is invoked.  @xref{Transient State}.
 
+@item
+@code{refresh-suffixes} Normally suffix objects and keymaps are only setup
+once, when the prefix is invoked.  Setting this to @code{t}, causes them to
+be recreated after every command.  This is useful when using @code{:if...}
+predicates, and those need to be rerun for some reason.  Doing this
+is somewhat costly, and there is a risk of losing state, so this is
+disabled by default and still considered experimental.
+
 @item
 @code{incompatible} A list of lists.  Each sub-list specifies a set of
 mutually exclusive arguments.  Enabling one of these arguments
 causes the others to be disabled.  An argument may appear in
-multiple sub-lists.
+multiple sub-lists.  Arguments must me given in the same form as
+used in the @code{argument} or @code{argument-format} slot of the respective
+suffix objects, usually something like @code{--switch} or @code{--option=%s}.  
For
+options and @code{transient-switches} suffixes it is also possible to match
+against a specific value, as returned by @code{transient-infix-value},
+for example, @code{--option=one}.
 
 @item
 @code{scope} For some transients it might be necessary to have a sort of
@@ -2099,8 +2179,14 @@ It must contain the following %-placeholders:
 @end itemize
 
 @item
-@code{description} The description, either a string or a function that is
-called with no argument and returns a string.
+@code{description} The description, either a string or a function, which is
+called with zero or one argument (the suffix object), and returns a
+string.
+
+@item
+@code{face} Face used for the description.  In simple cases it is easier
+to use this instead of using a function as @code{description} and adding
+the styling there.  @code{face} is appended using 
@code{add-face-text-property}.
 
 @item
 @code{show-help} A function used to display help for the suffix.  If
@@ -2189,8 +2275,10 @@ function that takes the object as the only argument and 
which
 returns a prompt string.
 
 @item
-@code{choices} A list of valid values.  How exactly that is used depends on
-the class of the object.
+@code{choices} A list of valid values, or a function that returns such a
+list.  The latter is not implemented for @code{transient-switches}, because
+I couldn't think of a use-case.  How exactly the choices are used
+varies depending on the class of the suffix.
 @end itemize
 
 @anchor{Slots of @code{transient-variable}}
@@ -2241,6 +2329,10 @@ what happens if you use more than one.
 @code{if-not-derived} Enable if major-mode does not derive from value.
 @end itemize
 
+By default these predicates run when the prefix command is invoked,
+but this can be changes, using the @code{refresh-suffixes} prefix slot.
+See @ref{Prefix Slots}.
+
 One more slot is shared between group and suffix classes, @code{level}.  Like
 the slots documented above, it is a predicate, but it is used for a
 different purpose.  The value has to be an integer between 1
@@ -2248,331 +2340,6 @@ and 7.  @code{level} controls whether a suffix or a 
group should be
 available depending on user preference.
 @xref{Enabling and Disabling Suffixes}.
 
-@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
-
-While transient commands were inspired by regular prefix keys and
-prefix arguments, they are also quite different and much more complex.
-
-The following diagrams illustrate some of the differences.
-
-@itemize
-@item
-@samp{(c)} represents a return to the command loop.
-@item
-@samp{(+)} represents the user's choice to press one key or another.
-@item
-@samp{@{WORD@}} are possible behaviors.
-@item
-@samp{@{NUMBER@}} is a footnote.
-@end itemize
-
-@anchor{Regular Prefix Commands}
-@subheading Regular Prefix Commands
-
-@xref{Prefix Keys,,,elisp,}.
-
-@example
-                                  ,--> command1 --> (c)
-                                  |
-(c)-(+)-> prefix command or key --+--> command2 --> (c)
-                                  |
-                                  `--> command3 --> (c)
-@end example
-
-@anchor{Regular Prefix Arguments}
-@subheading Regular Prefix Arguments
-
-@xref{Prefix Command Arguments,,,elisp,}.
-
-@example
-        ,----------------------------------,
-        |                                  |
-        v                                  |
-(c)-(+)---> prefix argument command --(c)-(+)-> any command --> (c)
-               |                                        ^        |
-               |                                        |        |
-               `-- sets or changes --, ,-- maybe used --'        |
-                                     | |                         |
-                                     v |                         |
-                          prefix argument state                  |
-                                      ^                          |
-                                      |                          |
-                                      `-------- discards --------'
-@end example
-
-@anchor{Transients}
-@subheading Transients
-
-(∩`-´)⊃━☆゚.*・。゚
-
-This diagram ignores the infix value and external state:
-
-@example
-(c)
- |        ,- @{stay@} ------<-,-<------------<-,-<---,
-(+)       |                 |                |     |
- |        |                 |                |     |
- |        |   ,--> infix1 --|                |     |
- |        |   |             |                |     |
- |        |   |--> infix2 --|                |     |
- v        v   |             |                |     |
- prefix -(c)-(+)-> infix3 --'                ^     |
-              |                              |     |
-              |---------------> suffix1 -->--|     |
-              |                              |     |
-              |---------------> suffix2 ----@{1@}------> @{exit@} --> (c)
-              |                                    |
-              |---------------> suffix3 -------------> @{exit@} --> (c)
-              |                                    |
-              `--> any command --@{2@}-> @{warn@} -->--|
-                                  |                |
-                                  |--> @{noop@} -->--|
-                                  |                |
-                                  |--> @{call@} -->--'
-                                  |
-                                  `------------------> @{exit@} --> (c)
-@end example
-
-This diagram takes the infix value into account to an extend, while
-still ignoring external state:
-
-@example
-(c)
- |        ,- @{stay@} ------<-,-<------------<-,-<---,
-(+)       |                 |                |     |
- |        |                 |                |     |
- |        |   ,--> infix1 --|                |     |
- |        |   |    |        |                |     |
- |        |   ,--> infix2 --|                |     |
- v        v   |    |        |                |     |
- prefix -(c)-(+)-> infix3 --'                |     |
-              |    |                         ^     |
-              |    |                         |     |
-              |---------------> suffix1 -->--|     |
-              |    |             ^           |     |
-              |    |             |           |     |
-              |---------------> suffix2 ----@{1@}------> @{exit@} --> (c)
-              |    |             ^                 |     |
-              |    |             |                 |     v
-              |    |             |                 |     |
-              |---------------> suffix3 -------------> @{exit@} --> (c)
-              |    |             ^                 |     |
-              | sets             |                 |     v
-              |    |             maybe             |     |
-              |    |             used              |     |
-              |    |             |                 |     |
-              |    |     infix --'                 |     |
-              |    `---> value                     |     |
-              |           ^                        |     |
-              |           |                        |     |
-              |       hides                        |     |
-              |           |                        |     |
-              |           `--------------------------<---|
-              |                                    |     |
-              `--> any command --@{2@}-> @{warn@} -->--|     |
-                                  |                |     |
-                                  |--> @{noop@} -->--|     |
-                                  |                |     |
-                                  |--> @{call@} -->--'     ^
-                                  |                      |
-                                  `------------------> @{exit@} --> (c)
-@end example
-
-This diagram provides more information about the infix value
-and also takes external state into account.
-
-@example
-                                       ,----sets--- "anything"
-                                       |
-                                       v
-                      ,---------> external
-                      |           state
-                      |            | |
-                      |  initialized |                      ☉‿⚆
-                   sets         from |
-                      |            | maybe
-                      | ,----------' used
-                      | |            |
-(c)                   | |            v
- |        ,- @{stay@} --|---<-,-<------|-----<-,-<---,
-(+)       |           | |   |        |       |     |
- |        |           | v   |        |       |     |
- |        |   ,--> infix1 --|        |       |     |
- |        |   |       | |   |        |       |     |
- |        |   |       | v   |        |       |     |
- |        |   ,--> infix2 --|        |       |     |
- |        |   |    | ^      |        |       |     |
- v        v   |    | |      |        |       |     |
- prefix -(c)-(+)-> infix3 --'        |       |     |
-              |    | ^               |       ^     |
-              |    | |               v       |     |
-              |---------------> suffix1 -->--|     |
-              |    | |            ^  |       |     |
-              |    | |            |  v       |     |
-              |---------------> suffix2 ----@{1@}------> @{exit@} --> (c)
-              |    | |            ^  |             |     |
-              |    | |            |  |             |     v
-              |    | |            |  v             |     |
-              |---------------> suffix3 -------------> @{exit@} --> (c)
-              |    | |            ^                |     |
-              | sets |            |                |     v
-              |    | initialized  maybe            |     |
-              |    | from         used             |     |
-              |    | |            |                |     |
-              |    | `-- infix ---'                |     |
-              |    `---> value -----------------------------> persistent
-              |           ^ ^                      |     |    across
-              |           | |                      |     |    invocations -,
-              |       hides |                      |     |                 |
-              |           | `----------------------------------------------'
-              |           |                        |     |
-              |           `--------------------------<---|
-              |                                    |     |
-              `--> any command --@{2@}-> @{warn@} -->--|     |
-                                  |                |     |
-                                  |--> @{noop@} -->--|     |
-                                  |                |     |
-                                  |--> @{call@} -->--'     ^
-                                  |                      |
-                                  `------------------> @{exit@} --> (c)
-@end example
-
-@itemize
-@item
-@samp{@{1@}} Transients can be configured to be exited when a suffix command
-is invoked.  The default is to do so for all suffixes except for
-those that are common to all transients and which are used to
-perform tasks such as providing help and saving the value of the
-infix arguments for future invocations.  The behavior can also be
-specified for individual suffix commands and may even depend on
-state.
-
-@item
-@samp{@{2@}} Transients can be configured to allow the user to invoke
-non-suffix commands.  The default is to not allow that and instead
-warn the user.
-@end itemize
-
-Despite already being rather complex, even the last diagram leaves out
-many details.  Most importantly it implies that the decision whether
-to remain transient is made later than it actually is made (for the
-most part a function on @code{pre-command-hook} is responsible).  But such
-implementation details are of little relevance to users and are
-covered elsewhere.
-
-@node Comparison With Other Packages
-@section Comparison With Other Packages
-
-@anchor{Magit-Popup}
-@subheading Magit-Popup
-
-Transient is the successor to Magit-Popup (@pxref{Top,,,magit-popup,}).
-
-One major difference between these two implementations of the same
-ideas is that while Transient uses transient keymaps and embraces the
-command-loop, Magit-Popup implemented an inferior mechanism that does
-not use transient keymaps and that instead of using the command-loop
-implements a naive alternative based on @code{read-char}.
-
-Magit-Popup does not use classes and generic functions and defining a
-new command type is near impossible as it involves adding hard-coded
-special-cases to many functions.  Because of that only a single new
-type was added, which was not already part of Magit-Popup's initial
-release.
-
-A lot of things are hard-coded in Magit-Popup.  One random example is
-that the key bindings for switches must begin with @code{-} and those for
-options must begin with @code{=}.
-
-@anchor{Hydra}
-@subheading Hydra
-
-Hydra (see @uref{https://github.com/abo-abo/hydra}) is another package that
-provides features similar to those of Transient.
-
-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''.
-
-Both hydras and transients can be used as simple command dispatchers.
-Used like this they are similar to regular prefix commands and prefix
-keys, except that the available commands are shown in the popup buffer.
-
-(Another package that does this is @code{which-key}. It does so automatically
-for any incomplete key sequence.  The advantage of that approach is
-that no additional work is necessary; the disadvantage is that the
-available commands are not organized semantically.)
-
-Both Hydra and Transient provide features that go beyond simple
-command dispatchers:
-
-@itemize
-@item
-Invoking a command from a hydra does not necessarily exit the hydra.
-That makes it possible to invoke the same command again, but using a
-shorter key sequence (i.e., the key that was used to enter the hydra
-does not have to be pressed again).
-
-Transient supports that too, but for now this feature is not a focus
-and the interface is a bit more complicated.  A very basic example
-using the current interface:
-
-@lisp
-(transient-define-prefix outline-navigate ()
-  :transient-suffix     'transient--do-stay
-  :transient-non-suffix 'transient--do-warn
-  [("p" "previous visible heading" outline-previous-visible-heading)
-   ("n" "next visible heading" outline-next-visible-heading)])
-@end lisp
-
-@item
-Transient supports infix arguments; values that are set by infix
-commands and then consumed by the invoked suffix command(s).
-
-To my knowledge, Hydra does not support that.
-@end itemize
-
-Both packages make it possible to specify how exactly the available
-commands are outlined:
-
-@itemize
-@item
-With Hydra this is often done using an explicit format string, which
-gives authors a lot of flexibility and makes it possible to do fancy
-things.
-
-The downside of this is that it becomes harder for a user to add
-additional commands to an existing hydra and to change key bindings.
-
-@item
-Transient allows the author of a transient to organize the commands
-into groups and the use of generic functions allows authors of
-transients to control exactly how a certain command type is
-displayed.
-
-However while Transient supports giving sections a heading it does
-not currently support giving the displayed information more
-structure by, for example, using box-drawing characters.
-
-That could be implemented by defining a new group class, which lets
-the author specify a format string.  It should be possible to
-implement that without modifying any existing code, but it does not
-currently exist.
-@end itemize
-
 @node FAQ
 @appendix FAQ
 
@@ -2584,10 +2351,10 @@ Yes, see @code{transient-display-buffer-action} in 
@ref{Configuration}.
 @anchor{How can I copy text from the popup buffer?}
 @appendixsec How can I copy text from the popup buffer?
 
-To be able to mark text in any transient popup buffer using the mouse,
-you have to add the following binding.  Note that the region won't be
-visualized, while doing so.  After you have quit the transient popup,
-you will be able to yank it another buffer.
+To be able to mark text in Transient's popup buffer using the mouse,
+you have to add the below binding.  Note that for technical reasons,
+the region won't be visualized, while doing so.  After you have quit
+the transient popup, you will be able to yank it in another buffer.
 
 @lisp
 (keymap-set transient-predicate-map
@@ -2595,6 +2362,16 @@ you will be able to yank it another buffer.
             #'transient--do-stay)
 @end lisp
 
+@anchor{How does Transient compare to prefix keys and universal arguments?}
+@appendixsec How does Transient compare to prefix keys and universal arguments?
+
+See 
@uref{https://github.com/magit/transient/wiki/Comparison-with-prefix-keys-and-universal-arguments}.
+
+@anchor{How does Transient compare to Magit-Popup and Hydra?}
+@appendixsec How does Transient compare to Magit-Popup and Hydra?
+
+See 
@uref{https://github.com/magit/transient/wiki/Comparison-with-other-packages}.
+
 @anchor{Why did some of the key bindings change?}
 @appendixsec Why did some of the key bindings change?
 
@@ -2657,7 +2434,7 @@ for @kbd{q}.
 If you want to get @kbd{q}'s old binding back then you can do so.  Doing
 that is a bit more complicated than changing a single key binding, so
 I have implemented a function, @code{transient-bind-q-to-quit} that makes the
-necessary changes.  See its doc string for more information.
+necessary changes.  See its documentation string for more information.
 
 @node Keystroke Index
 @appendix Keystroke Index
diff --git a/doc/misc/url.texi b/doc/misc/url.texi
index 6517f858324..3a447a20559 100644
--- a/doc/misc/url.texi
+++ b/doc/misc/url.texi
@@ -1231,8 +1231,6 @@ the @file{*URL-DEBUG*} buffer.
 A number means log all messages and show them with @code{message}.
 It may also be a list of the types of messages to be logged.
 @end defopt
-@defopt url-personal-mail-address
-@end defopt
 @defopt url-privacy-level
 @end defopt
 @defopt url-lastloc-privacy-level
diff --git a/doc/misc/widget.texi b/doc/misc/widget.texi
index eb411f29c5c..e8b41315000 100644
--- a/doc/misc/widget.texi
+++ b/doc/misc/widget.texi
@@ -1703,7 +1703,7 @@ A variable that holds the history of field minibuffer 
edits.
 
 @item :prompt-value
 A function that uses the @code{:prompt-internal} function and the
-@code{:prompt-history} value to prompt for a string, and retun the
+@code{:prompt-history} value to prompt for a string, and return the
 user response in the external format.
 
 @item :action
@@ -1714,7 +1714,7 @@ Function that takes care of creating the widget, 
respecting its
 @code{:size} and @code{:value}.
 
 @item :value-set
-Function to use to modify programatically the current value of the
+Function to use to modify programmatically the current value of the
 widget.
 
 @item :value-delete
@@ -2455,7 +2455,7 @@ difference from the @code{const} widget is that they will 
allow the
 user to see the variable or function documentation for the symbol.
 
 This is accomplished via using the @samp{%h} format escape, and adding
-an appropiate @code{:documentation-property} function for each widget.
+an appropriate @code{:documentation-property} function for each widget.
 
 @deffn Widget variable-item
 An immutable symbol that is bound as a variable.
diff --git a/etc/DEBUG b/etc/DEBUG
index 5aeb38c6460..86bff45e7d9 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -1142,7 +1142,7 @@ one to upload, like so:
   ../java/debug.sh --gdbserver /path/to/gdbserver
 
 This Gdbserver should be statically linked or compiled using the
-Android NDK, and must target the same architecture as the debugee
+Android NDK, and must target the same architecture as the debugged
 Emacs binary.  Older versions of the Android NDK (such as r24)
 distribute suitable Gdbserver binaries, usually located within
 
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index 7b39af03a88..c883f575c15 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -131,13 +131,6 @@ connectivity before attempting to reconnect in earnest.  
See option
 'erc-server-reconnect-function' and new local module 'services-regain'
 (also experimental) to get started.
 
-** Module 'fill' can add a bit of space between messages.
-On graphical displays, it's now possible to add some breathing room
-around certain messages via the new option 'erc-fill-line-spacing'.
-This is especially handy when using the option 'erc-fill-wrap-merge'
-to omit repeated speaker tags, which can make message boundaries less
-detectable by tired eyes.
-
 ** Modules rather than their libraries set major-mode keybindings.
 To put it another way, simply loading a built-in module's library no
 longer modifies 'erc-mode-map'.  Instead, modifications occur during
@@ -170,6 +163,19 @@ options, like 'erc-command-indicator', have moved to the 
'erc-goodies'
 library, although their Custom groups remain the same.  Add
 'command-indicator' to 'erc-modules' to get started.
 
+** Option 'erc-track-faces-normal-list' slightly more influential.
+This option has always been a source of confusion for users, mainly
+because its influence rode heavily on the makeup of faces in a given
+message.  Historically, when a buffer's current mode-line face was a
+member of this option's value, ERC would only swap it out for a fellow
+"normal" if it was absent from the message being processed.  Beginning
+with this release, ERC now looks to other ranked and, if necessary,
+unranked "normals" instead of sustaining the same face between
+messages.  This was done to better honor the stated purpose of the
+option, which is to provide consistent visual feedback when buffer
+activity occurs.  If you experience problems with this development,
+see the compatibility flag 'erc-track-ignore-normal-contenders-p'.
+
 ** 'erc-button-alist' and 'erc-nick-popup-alist' have evolved slightly.
 It's no secret that the 'buttons' module treats potential nicknames
 specially.  This is perhaps most evident in its treatment of the
@@ -184,6 +190,23 @@ s-expressions, which ERC will continue to honor.  Although 
the default
 lineup remains functionally equivalent, its members have all been
 updated accordingly.
 
+** 'erc-track-faces-priority-list' and 'erc-track-faces-normal-list' slimmed.
+These options have been purged of certain 'button'-related face
+combinations.  Originally added in ERC 5.3, these combinations
+described the effect of "buttonizing" atop faces added by the 'match'
+module, like '(erc-nick-default-face erc-pal-face)'.  However, since
+at least Emacs 27, 'match' has run before 'button' in
+'erc-insert-modify-hook', meaning such permutations aren't possible.
+
+More importantly, users who've customized either of these options
+should update them with the new default value of the option
+'erc-button-nickname-face'.  Like 'erc-nick-default-face', which it
+replaces, the new 'erc-button-nick-default-face' is also a "real"
+face.  Its sole reason for existing is to make it easier for users and
+modules to distinguish between basic buttonized faces and
+'erc-nick-default-face', which is now reserved to mean the base
+"speaker" face.
+
 ** Option 'erc-query-on-unjoined-chan-privmsg' restored and renamed.
 This option was accidentally removed from the default client in ERC
 5.5 and was thus prevented from influencing PRIVMSG routing.  It's now
@@ -214,7 +237,17 @@ Users of the default theme may notice that 
'erc-action-face' and
 'erc-notice-face' now appear slightly less bold on systems supporting
 a weight of 'semi-bold'.  This was done to make buttons detectable and
 to spare users from resorting to tweaking these faces, or options like
-'erc-notice-highlight-type', just to achieve this effect.
+'erc-notice-highlight-type', just to achieve this effect.  It's
+currently most prominent in "/ME" messages, where 'erc-action-face'
+sits beneath 'erc-input-face', as well as 'erc-my-nick-face' in the
+speaker portion.
+
+** Fewer nick buttons in QUIT, JOIN, and PART messages.
+Common messages that show a nickname followed by a "userhost" often
+end up with redundant buttons because the nick reappears in or is the
+same as the "~user" portion.  ERC now tamps down on this to make
+<TAB>ing around more convenient.  To opt out, see the new variable
+'erc-button-highlight-nick-once'.
 
 ** Improved interplay between buffer truncation and message logging.
 While most of these improvements are subtle, some affect everyday use.
@@ -272,6 +305,26 @@ buffers.  In channels, it's grown to include all letters 
and their
 possibly truncated arguments, with the exception of stateful list
 modes, like "b".
 
+** In-buffer "status messages" are now a thing.
+The ancient option 'erc-ensure-target-buffer-on-privmsg' has been
+repurposed slightly to express a third state denoted by the symbol
+'status'.  It tells ERC to revert to the old default behavior in which
+separate, "pseudo" target buffers for status-prefixed conversing
+co-existed alongside actual target buffers.  Instead of this awkward
+arrangement, ERC now acts like other clients by default and inserts
+so-called "status messages" in situ, right between other messages.
+Similar insertion-routing behavior now also applies to CTCP ACTIONs
+directed at status-prefixed channels.  Unfortunately, outgoing "/msg
+@#chan hi" messages aren't yet shown in the same fashion, but the
+groundwork has been laid, making such an addition almost trivial.
+
+** An easier way to see channel-membership prefixes on speakers.
+The option 'erc-format-@nick' has been deprecated in favor of the new
+boolean option 'erc-show-speaker-membership-status', a simple switch
+to enable the displaying of status prefixes on the speaker nicks of
+incoming chat messages.  Prefixes on your speaker nick for outgoing
+chat messages continue to always be present.
+
 ** Miscellaneous UX changes.
 Some minor quality-of-life niceties have finally made their way to
 ERC.  For example, fool visibility has become togglable with the new
@@ -306,6 +359,15 @@ from 't' to the more useful 'erc-prompt', although the 
property of the
 same name has been retained and now has a value of 'hidden' when
 disconnected.
 
+*** Lists of faces in buttonized text are no longer nested.
+Previously, when "buttonizing" a new region, ERC would combine faces
+by blindly consing the new onto the existing.  In theory, this kept a
+nice record of all modifications to a given region.  However, it also
+complicated life for other modules wanting to analyze and operate on
+these regions.  Beginning with this release, ERC now merges combined
+faces together when creating buttons, although the odd nested list may
+still crop up here and there.
+
 *** Members of insert- and send-related hooks have been reordered.
 As anyone reading this is no doubt aware, both built-in and
 third-party modules rely on certain hooks for adjusting incoming and
@@ -425,11 +487,44 @@ Built-in modules can now provide more detailed help for a 
particular
 subcommand by telling ERC to defer to a specialized handler.  This
 facility can be opened up to third parties should any one request it.
 
+*** Message-formatting templates in 'notify' renamed.
+All templates beginning with the prefix "erc-message-english-notify_"
+have been renamed to begin with "erc-message-english-notify-".  For
+example, the variable 'erc-message-english-notify_current' is now
+'erc-message-english-notify_current'.  The old names have been
+preserved as obsolete aliases.
+
 *** Longtime quasi modules made proper.
 The 'fill' module is now defined by 'define-erc-module'.  The same
 goes for ERC's imenu integration, which has 'imenu' now appearing in
 the default value of 'erc-modules'.
 
+*** Function 'erc-get-user-mode-prefix' renamed.
+This utility has been renamed to 'erc-get-channel-membership-prefix'
+to better reflect its role of delivering a formatted "status prefix",
+like "+" (for "voice"), and to avoid confusion with user modes, like
+"+i" (for "invisible").  Additionally, its lone parameter is now
+overloaded to accept an 'erc-channel-user' object as well as a string.
+
+*** Channel-membership table 'erc-channel-users' renamed.
+Distinguishing between 'erc-channel-user' objects and values of the
+'erc-channel-users' (plural) hash-table has been a constant source of
+confusion, even within ERC's own code base.  The hash-table's values
+are cons cells whose CDR slot is an 'erc-channel-user'.  To help keep
+things sane, 'erc-channel-users' (plural) is now officially being
+redubbed 'erc-channel-members'.  Similarly, the utility function
+'erc-get-channel-user' has been renamed to 'erc-get-channel-member'.
+Expect deprecations of the old names to follow in a future release.
+
+*** The 'erc-channel-user' struct has a changed internally.
+The five boolean slots for membership prefixes have been folded
+("encoded") into a single integer slot.  However, the old 'setf'-able
+accessors remain available, and the constructor's signature remains
+unchanged.  Since third-party code must be recompiled when upgrading
+ERC anyway, users shouldn't experience any churn.  The only caveat is
+that third-party code using the literal read-syntax of these objects,
+for example, in unit tests, will have to be updated.
+
 *** Hidden messages contain a preceding rather than trailing newline.
 ERC has traditionally only offered to hide messages involving fools,
 but plans are to make hiding more powerful.  Anyone depending on the
@@ -457,8 +552,9 @@ ERC now adjusts input lines to fall within allowed length 
limits
 before showing hook members the result.  For compatibility,
 third-party code can request that the final input be adjusted again
 prior to being sent.  To facilitate this, the 'erc-input' object
-shared among hook members has gained a new 'refoldp' slot, making this
-a breaking change, if only in theory.  See doc string for details.
+shared among hook members has gained a "phony" 'refoldp' slot that's
+only accessible from 'erc-pre-send-functions'.  See doc string for
+details.
 
 *** ERC's prompt survives the insertion of user input and messages.
 Previously, ERC's prompt and its input marker disappeared while
@@ -510,6 +606,43 @@ handling specific "MODE" types and letters in coming 
releases.  If
 you'd like a say in shaping how this transpires, please share your
 ideas and use cases on the tracker.
 
+*** A better way to define message-formatting templates.
+The functions 'erc-define-catalog-entry' and 'erc-define-catalog' have
+been deprecated in favor of 'erc-define-message-format-catalog', a new
+macro for defining template "catalogs" at the top level of libraries.
+
+*** Interface for determining display names renamed.
+The option 'erc-format-nick-function' has been renamed to
+'erc-speaker-from-channel-member-function' to better reflect its
+actual role.  So too has the related function 'erc-format-nick', which
+is now 'erc-determine-speaker-from user'.
+
+*** A template-based approach to formatting inserted chat messages.
+Predicting and influencing how ERC formats messages containing a
+leading "<speaker>" has never been straightforward.  The characters
+bracketing the speaker and the faces used for each component have
+always been hard-coded, with 'erc-format-query-as-channel-p' being the
+only knob of any consequence.  With this release, ERC begins its
+transition to a unified formatting paradigm that builds upon the
+already familiar "language catalog" templating system.  Using a
+separate "speaker catalog" keyed by contextual symbols, like
+'query-privmsg', ERC (and eventually everyone) will more easily be
+able to influence how inserted messages take shape in buffers.
+
+*** New format templates for inserted CTCP ACTION messages.
+In 5.5 and earlier, ERC displayed outgoing CTCP ACTION messages in
+'erc-input-face' alone (before buttonizing).  Incoming ACTION messages
+mirrored this, except with 'erc-action-face' throughout.  Going
+forward, inserted outgoing "/ME" messages will also incorporate
+'erc-action-face', only underneath 'erc-input-face', with
+'erc-my-nick-face' sitting atop both in the leading "speaker" nickname
+portion (again, pre-buttonizing).  This new behavior sidesteps the
+traditional format template 'erc-message-english-ACTION' from the
+default "language catalog" in favor of an entry from the new internal
+"speaker catalog".  Users needing to access the old behavior can do so
+by toggling a provided compatibility switch.  See source code around
+the function 'erc-send-action' for details.
+
 *** Miscellaneous changes
 Two helper macros from GNU ELPA's Compat library are now available to
 third-party modules as 'erc-compat-call' and 'erc-compat-function'.
@@ -1706,7 +1839,7 @@ Only the macros in cl-macs.el are used.
 
 ** Make flood protection toggle-able as on/off, removing the 'strict option.
 
-** If possible, re-use channel buffers when reconnecting to a server.
+** If possible, reuse channel buffers when reconnecting to a server.
 
 ** Text in ERC buffers is now read-only by default.
 To get the previous behavior,
diff --git a/etc/NEWS b/etc/NEWS
index da00ea9dbda..90ff23b7937 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -37,7 +37,7 @@ See the file 'java/INSTALL' for more details.
 libgccjit is present and functional on the system.  To disable native
 compilation, configure Emacs with the option:
 
-  $ ./configure --with-native-compilation=no
+    ./configure --with-native-compilation=no
 
 ---
 ** Emacs now defaults to ossaudio library for sound on NetBSD and OpenBSD.
@@ -66,6 +66,21 @@ URI scheme.  See the Org mode manual, Info node "(org) 
Protocols" for
 more details.
 
 
+* Incompatible Changes in Emacs 30.1
+
++++
+** URL now never sends user email addresses in HTTP requests.
+Emacs never sent email addresses by default, but it used to be
+possible to customize 'url-privacy-level' so that the users email
+address was sent along in HTTP requests.  This feature has now been
+removed, as it was considered more dangerous than useful.  RFC 9110
+(§ 10.1.2) also recommends against it.  The user option
+'url-personal-mail-address' is now also obsolete.
+
+To send an email address in the header of individual HTTP requests,
+see the variable `url-request-extra-headers'.
+
+
 * Changes in Emacs 30.1
 
 ** Emacs now supports Unicode Standard version 15.1.
@@ -242,7 +257,7 @@ It can be used to customize the look of the appointment 
notification
 displayed on the mode line when 'appt-display-mode-line' is non-nil.
 
 ---
-*** Emacs now recognizes shebang lines that pass -S/--split-string to 'env'.
+*** Emacs now recognizes shebang lines that pass '-S'/'--split-string' to 
'env'.
 When visiting a script that invokes 'env -S INTERPRETER ARGS...' in
 its shebang line, Emacs will now skip over 'env -S' and deduce the
 major mode based on the interpreter after 'env -S'.
@@ -258,6 +273,11 @@ called in the '--eval' expression, which is useful when 
those
 arguments contain arbitrary characters that otherwise might require
 elaborate and error-prone escaping (to protect them from the shell).
 
++++
+** 'recover-file' can show diffs between auto save file and current file.
+When answering the prompt with "diff" or "=", it now shows the diffs
+between the auto save file and the current file.
+
 
 * Editing Changes in Emacs 30.1
 
@@ -348,7 +368,7 @@ functions in CJK locales.
 *** New input methods for the Urdu, Pashto, and Sindhi languages.
 These languages are spoken in Pakistan and Afganistan.
 
-*** Additional 'C-x 8' key translations for æ and Æ.
+*** Additional 'C-x 8' key translations for "æ" and "Æ".
 These characters can now be input with 'C-x 8 a e' and 'C-x 8 A E',
 respectively, in addition to the existing translations 'C-x 8 / e' and
 'C-x 8 / E'.
@@ -425,7 +445,7 @@ The look of the key prompt in the project switcher has been 
changed
 slightly.  To get the previous one, set this option to 'brackets'.
 
 *** 'project-try-vc' tries harder to find the responsible VCS.
-When 'project-vc-extra-root-markers' is non-nil, and causes
+When 'project-vc-extra-root-markers' is non-nil, and causes a
 subdirectory project to be detected which is not a VCS root, we now
 additionally traverse the parent directories until a VCS root is found
 (if any), so that the ignore rules for that repository are used, and
@@ -439,7 +459,7 @@ have access to all keys defined inside 
'project-prefix-map', as well
 as global bindings (to run other commands inside the project root),
 you can add this to your init script:
 
-  (setopt project-switch-commands #'project-prefix-or-any-command)
+    (setopt project-switch-commands #'project-prefix-or-any-command)
 
 ** VC
 
@@ -457,6 +477,19 @@ With this value only the revision number is displayed on 
the mode-line.
 *** Obsolete command 'vc-switch-backend' re-added as 'vc-change-backend'.
 The command was previously obsoleted and unbound in Emacs 28.
 
+*** Support for viewing VC change history across renames.
+When a fileset's VC change history ('C-x v l') ends at a rename, we
+now print the old name(s) and a button which jumps to their history.
+Git and Hg are supported.  Naturally, 'vc-git-print-log-follow' should
+be nil for this to work (or '--follow' should not be in
+'vc-hg-print-log-switches', in Hg's case).  Unlike when the '--follow'
+switch is used, commands to see the diff of the old revision ('d'),
+check out an old file version ('f') or annotate it right away ('a'),
+also work on revisions which precede renames.
+
+*** New option 'vc-git-file-name-changes-switches'.
+It allows tweaking the thresholds for rename and copy detection.
+
 ** Diff mode
 
 +++
@@ -498,7 +531,7 @@ the last line will move to the first line).  The default is 
nil.
 
 *** New user option 'dired-filename-display-length'.
 It is an integer representing the maximum display length of filenames.
-The middle part of filename whose length exceeds the restriction is
+The middle part of a filename whose length exceeds the restriction is
 hidden and an ellipsis is displayed instead.  A value of 'window'
 means using the right edge of window as the display restriction.  The
 default is nil.
@@ -511,6 +544,16 @@ based on marked files in Dired.  Possible backends are
 and a universal command such as "open" or "start"
 that delegates to the OS.
 
+*** New command 'dired-do-open'.
+This command is bound to "Open" in the context menu; it "opens" the
+marked or clicked on files according to the OS conventions.  For
+example, on systems supporting XDG, this runs 'xdg-open' on the
+files.
+
++++
+*** 'dired-listing-switches' handles connection-local values if exist.
+This allows to customize different switches for different remote machines.
+
 ** Ediff
 
 ---
@@ -613,21 +656,43 @@ calling external rgrep.
 +++
 *** If a command exits abnormally, the Eshell prompt now shows its exit code.
 
++++
+*** New user option 'eshell-history-append'.
+If non-nil, each Eshell session will save history by appending new
+entries of that session to the history file rather than overwriting
+the file with the whole history of the session.  The default is nil.
+
 ** Minibuffer and Completions
 
 *** New commands 'previous-line-completion' and 'next-line-completion'.
-Bound to '<UP>' and '<DOWN>' arrow keys, respectively, they navigate
+Bound to '<up>' and '<down>' arrow keys, respectively, they navigate
 the "*Completions*" buffer vertically by lines, wrapping at the
 top/bottom when 'completion-auto-wrap' is non-nil.
 
 *** New user option 'minibuffer-visible-completions'.
-When customized to non-nil, you can use arrow key in the minibuffer
-to navigate the completions displayed in the *Completions* window.
+When customized to non-nil, you can use arrow keys in the minibuffer
+to navigate the completions displayed in the "*Completions*" window.
 Typing 'RET' selects the highlighted candidate.  'C-g' hides the
 completions window.  When the completions window is not visible,
 then all these keys have their usual meaning in the minibuffer.
 This option is supported for in-buffer completion as well.
 
+*** Selected completion candidates are deselected on typing.
+When you type at the minibuffer prompt, the current completion
+candidate will be un-highlighted, and point in the "*Completions*" window
+will be moved off that candidate.  'minibuffer-choose-completion'
+('M-RET') will still choose a previously-selected completion
+candidate, but the new command 'minibuffer-choose-completion-or-exit'
+(bound to 'RET' by 'minibuffer-visible-completions') will exit with
+the minibuffer contents instead.  This deselection behavior can be
+controlled with the new user option 'completion-auto-deselect', which
+is t by default.
+
+*** New value 'historical' for user option 'completions-sort'.
+When 'completions-sort' is set to 'historical', completion candidates
+will be first sorted alphabetically, and then re-sorted by their order
+in the minibuffer history, with more recent candidates appearing first.
+
 ** Pcomplete
 
 ---
@@ -640,7 +705,7 @@ suppress remote file name completion at all.
 *** Completion for the 'doas' command has been added.
 Command completion for 'doas' in Eshell and Shell mode will now work.
 
-** Shell Mode
+** Shell mode
 
 +++
 *** New user option 'shell-get-old-input-include-continuation-lines'.
@@ -856,7 +921,7 @@ distracting and easily confused with actual code, or a 
significant
 early aid that relieves you from moving the buffer or reaching for the
 mouse to consult an error message.
 
-** JS Mode
+** JS mode.
 The binding 'M-.' has been removed from the major mode keymaps in
 'js-mode' and 'js-ts-mode', having it default to the global binding
 which calls 'xref-find-definitions'.  If the previous one worked
@@ -1038,6 +1103,12 @@ This can help avoid some awkward skip conditions.  For 
example
 '(skip-unless (not noninteractive))' can be changed to the easier
 to read '(skip-when noninteractive)'.
 
++++
+*** Syntax highlighting unit testing support.
+An ERT extension ('ert-font-lock') now provides support for face
+assignment unit testing.  For more information, see the "(ert) Syntax
+Highlighting Tests" node in the ERT manual.
+
 ** URL
 
 +++
@@ -1142,8 +1213,9 @@ showcases all their customization options.
 
 ---
 ** 'register-preview-delay' is no longer used.
-Register preview is no more delayed.  If you want to disable it use
-'register-use-preview' instead with a boolean value.
+Register preview is no longer delayed.  If you want to disable the
+preview, customize the new option 'register-use-preview' to the value
+'never'.
 
 +++
 ** 'M-TAB' now invokes 'completion-at-point' also in Text mode.
@@ -1151,7 +1223,7 @@ Text mode no longer binds 'M-TAB' to 
'ispell-complete-word', and
 instead this mode arranges for 'completion-at-point', globally bound
 to 'M-TAB', to perform word completion as well.  If you want 'M-TAB'
 to invoke 'ispell-complete-word', as it did in previous Emacs
-versions, customize the new option
+versions, customize the new user option
 'text-mode-meta-tab-ispell-complete-word' to non-nil.
 
 ** 'pp' and 'pp-to-string' now always include a terminating newline.
@@ -1185,7 +1257,7 @@ This user option has been obsoleted in Emacs 27, use
 ---
 ** User options 'eshell-NAME-unload-hook' are now obsolete.
 These hooks were named incorrectly, and so they never actually ran
-when unloading the correspending feature.  Instead, you should use
+when unloading the corresponding feature.  Instead, you should use
 hooks named after the feature name, like 'esh-mode-unload-hook'.
 
 +++
@@ -1254,6 +1326,10 @@ values.
 
 * Lisp Changes in Emacs 30.1
 
+** New 'pop-up-frames' action alist entry for 'display-buffer'.
+This has the same effect as the variable of the same name and takes
+precedence over the variable when present.
+
 ** New function 'merge-ordered-lists'.
 Mostly used internally to do a kind of topological sort of
 inheritance hierarchies.
@@ -1261,14 +1337,14 @@ inheritance hierarchies.
 ** New API for 'derived-mode-p' and control of the graph of major modes.
 
 *** 'derived-mode-p' now takes the list of modes as a single argument.
-The same holds for `provided-mode-derived-p`.
+The same holds for 'provided-mode-derived-p'.
 The old calling convention where multiple modes are passed as
 separate arguments is deprecated.
 
 *** New functions to access the graph of major modes.
 While 'define-derived-mode' still only supports single inheritance,
 modes can declare additional parents (for tests like 'derived-mode-p')
-with `derived-mode-add-parents`.
+with 'derived-mode-add-parents'.
 Accessing the 'derived-mode-parent' property directly is now
 deprecated in favor of the new functions 'derived-mode-set-parent'
 and 'derived-mode-all-parents'.
@@ -1613,6 +1689,14 @@ A 5th argument, optional, has been added to
 'modify-dir-local-variable'.  It can be used to specify which
 dir-locals file to modify.
 
+** Connection local variables
+
++++
+*** New macros 'connection-local-p' and 'connection-local-value'.
+The former macro returns non-nil if a variable has a connection-local
+binding.  The latter macro returns the connection-local value of a
+variable if any, or its current value.
+
 
 * Changes in Emacs 30.1 on Non-Free Operating Systems
 
diff --git a/etc/ORG-NEWS b/etc/ORG-NEWS
index 5f92c056018..1e87f10748f 100644
--- a/etc/ORG-NEWS
+++ b/etc/ORG-NEWS
@@ -1098,7 +1098,7 @@ Conversion to SVG exposes a number of additional 
customizations that
 give the user full control over the contents of the latex source
 block. ~org-babel-latex-preamble~, ~org-babel-latex-begin-env~ and
 ~org-babel-latex-end-env~ are new customization options added to allow
-the user to specify the preamble and code that preceedes and proceeds
+the user to specify the preamble and code that precedes and proceeds
 the contents of the source block.
 
 *** New option ~org-html-meta-tags~ allows for HTML meta tags customization
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index fdce1bc81ba..e42e3c4d87a 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -2014,7 +2014,7 @@ remote X server, try this:
 
 *** Dropping text on xterm doesn't work.
 
-Emacs sends sythetic button events to legacy clients such as xterm
+Emacs sends synthetic button events to legacy clients such as xterm
 that do not support either the XDND or Motif drag-and-drop protocols
 in order to "paste" the text that was dropped.  Unfortunately, xterm
 is configured to ignore these events by default.  Add the following to
@@ -3539,7 +3539,7 @@ The Microsoft scaler and FreeType promptly disregard such 
points.
 
 Nothing in the TrueType specifications implies that points "hidden" in
 this fashion should be afforded any special treatment, and thus Emacs
-eschews doing so.  Consequentially, black streaks are displayed as
+eschews doing so.  Consequently, black streaks are displayed as
 Emacs interpolates glyph edges between points within the glyph and
 points the test font attempts to hide.
 
diff --git a/etc/images/symbols/minus_16.pbm b/etc/images/symbols/minus_16.pbm
index 4f73340f179..c564ca290d8 100644
Binary files a/etc/images/symbols/minus_16.pbm and 
b/etc/images/symbols/minus_16.pbm differ
diff --git a/etc/images/symbols/minus_16.svg b/etc/images/symbols/minus_16.svg
index 9cb61d8d379..f0769763e5d 100644
--- a/etc/images/symbols/minus_16.svg
+++ b/etc/images/symbols/minus_16.svg
@@ -1,3 +1,3 @@
 <svg width="16" height="16" viewBox="0 0 16 16"  
xmlns="http://www.w3.org/2000/svg";>
-<path d="M13 7H3V9H13V7Z" />
+<path d="M12.5 7H3.5V9H12.5V7Z" />
 </svg>
diff --git a/etc/images/symbols/plus_16.pbm b/etc/images/symbols/plus_16.pbm
index c369231b636..2d8a45a5db4 100644
Binary files a/etc/images/symbols/plus_16.pbm and 
b/etc/images/symbols/plus_16.pbm differ
diff --git a/etc/images/symbols/plus_16.svg b/etc/images/symbols/plus_16.svg
index a4d2f84f318..573a5e5ca76 100644
--- a/etc/images/symbols/plus_16.svg
+++ b/etc/images/symbols/plus_16.svg
@@ -1,3 +1,3 @@
 <svg width="16" height="16" viewBox="0 0 16 16"  
xmlns="http://www.w3.org/2000/svg";>
-<path d="M9 3H7V7H3V9H7V13H9V9H13V7H9V3Z" />
+<path d="M9 3.5H7V7H3.5V9H7V12.5H9V9H12.5V7H9V3.5Z" />
 </svg>
diff --git a/etc/publicsuffix.txt b/etc/publicsuffix.txt
index 956110851a4..79248a73f04 100644
--- a/etc/publicsuffix.txt
+++ b/etc/publicsuffix.txt
@@ -6710,7 +6710,7 @@ org.zw
 
 // newGTLDs
 
-// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2023-09-30T15:11:25Z
+// List of new gTLDs imported from 
https://www.icann.org/resources/registries/gtlds/v2/gtlds.json on 
2023-12-06T15:14:09Z
 // This list is auto-generated, don't edit it manually.
 // aaa : American Automobile Association, Inc.
 // https://www.iana.org/domains/root/db/aaa.html
@@ -7400,10 +7400,6 @@ cbn
 // https://www.iana.org/domains/root/db/cbre.html
 cbre
 
-// cbs : CBS Domains Inc.
-// https://www.iana.org/domains/root/db/cbs.html
-cbs
-
 // center : Binky Moon, LLC
 // https://www.iana.org/domains/root/db/center.html
 center
@@ -7492,10 +7488,6 @@ citic
 // https://www.iana.org/domains/root/db/city.html
 city
 
-// cityeats : Lifestyle Domain Holdings, Inc.
-// https://www.iana.org/domains/root/db/cityeats.html
-cityeats
-
 // claims : Binky Moon, LLC
 // https://www.iana.org/domains/root/db/claims.html
 claims
@@ -7760,7 +7752,7 @@ dental
 // https://www.iana.org/domains/root/db/dentist.html
 dentist
 
-// desi : Desi Networks LLC
+// desi
 // https://www.iana.org/domains/root/db/desi.html
 desi
 
@@ -7808,7 +7800,7 @@ discover
 // https://www.iana.org/domains/root/db/dish.html
 dish
 
-// diy : Lifestyle Domain Holdings, Inc.
+// diy : Internet Naming Company LLC
 // https://www.iana.org/domains/root/db/diy.html
 diy
 
@@ -7940,10 +7932,6 @@ esq
 // https://www.iana.org/domains/root/db/estate.html
 estate
 
-// etisalat : Emirates Telecommunications Corporation (trading as Etisalat)
-// https://www.iana.org/domains/root/db/etisalat.html
-etisalat
-
 // eurovision : European Broadcasting Union (EBU)
 // https://www.iana.org/domains/root/db/eurovision.html
 eurovision
@@ -8116,7 +8104,7 @@ fly
 // https://www.iana.org/domains/root/db/foo.html
 foo
 
-// food : Lifestyle Domain Holdings, Inc.
+// food : Internet Naming Company LLC
 // https://www.iana.org/domains/root/db/food.html
 food
 
@@ -8164,10 +8152,6 @@ frl
 // https://www.iana.org/domains/root/db/frogans.html
 frogans
 
-// frontdoor : Lifestyle Domain Holdings, Inc.
-// https://www.iana.org/domains/root/db/frontdoor.html
-frontdoor
-
 // frontier : Frontier Communications Corporation
 // https://www.iana.org/domains/root/db/frontier.html
 frontier
@@ -8328,7 +8312,7 @@ goldpoint
 // https://www.iana.org/domains/root/db/golf.html
 golf
 
-// goo : NTT Resonant Inc.
+// goo : NTT DOCOMO, INC.
 // https://www.iana.org/domains/root/db/goo.html
 goo
 
@@ -8780,10 +8764,6 @@ kids
 // https://www.iana.org/domains/root/db/kim.html
 kim
 
-// kinder : Ferrero Trading Lux S.A.
-// https://www.iana.org/domains/root/db/kinder.html
-kinder
-
 // kindle : Amazon Registry Services, Inc.
 // https://www.iana.org/domains/root/db/kindle.html
 kindle
@@ -8928,7 +8908,7 @@ life
 // https://www.iana.org/domains/root/db/lifeinsurance.html
 lifeinsurance
 
-// lifestyle : Lifestyle Domain Holdings, Inc.
+// lifestyle : Internet Naming Company LLC
 // https://www.iana.org/domains/root/db/lifestyle.html
 lifestyle
 
@@ -8968,7 +8948,7 @@ lipsy
 // https://www.iana.org/domains/root/db/live.html
 live
 
-// living : Lifestyle Domain Holdings, Inc.
+// living : Internet Naming Company LLC
 // https://www.iana.org/domains/root/db/living.html
 living
 
@@ -9672,7 +9652,7 @@ promo
 // https://www.iana.org/domains/root/db/properties.html
 properties
 
-// property : Internet Naming Company LLC
+// property : Digital Property Infrastructure Limited
 // https://www.iana.org/domains/root/db/property.html
 property
 
@@ -9836,10 +9816,6 @@ rio
 // https://www.iana.org/domains/root/db/rip.html
 rip
 
-// rocher : Ferrero Trading Lux S.A.
-// https://www.iana.org/domains/root/db/rocher.html
-rocher
-
 // rocks : Dog Beach, LLC
 // https://www.iana.org/domains/root/db/rocks.html
 rocks
@@ -10088,10 +10064,6 @@ shouji
 // https://www.iana.org/domains/root/db/show.html
 show
 
-// showtime : CBS Domains Inc.
-// https://www.iana.org/domains/root/db/showtime.html
-showtime
-
 // silk : Amazon Registry Services, Inc.
 // https://www.iana.org/domains/root/db/silk.html
 silk
@@ -10552,7 +10524,7 @@ ups
 // https://www.iana.org/domains/root/db/vacations.html
 vacations
 
-// vana : Lifestyle Domain Holdings, Inc.
+// vana : Internet Naming Company LLC
 // https://www.iana.org/domains/root/db/vana.html
 vana
 
@@ -10636,10 +10608,6 @@ vlaanderen
 // https://www.iana.org/domains/root/db/vodka.html
 vodka
 
-// volkswagen : Volkswagen Group of America Inc.
-// https://www.iana.org/domains/root/db/volkswagen.html
-volkswagen
-
 // volvo : Volvo Holding Sverige Aktiebolag
 // https://www.iana.org/domains/root/db/volvo.html
 volvo
@@ -10708,6 +10676,10 @@ weber
 // https://www.iana.org/domains/root/db/website.html
 website
 
+// wed
+// https://www.iana.org/domains/root/db/wed.html
+wed
+
 // wedding : Registry Services, LLC
 // https://www.iana.org/domains/root/db/wedding.html
 wedding
@@ -11040,10 +11012,6 @@ xin
 // https://www.iana.org/domains/root/db/xn--mgba7c0bbn0a.html
 العليان
 
-// xn--mgbaakc7dvf : Emirates Telecommunications Corporation (trading as 
Etisalat)
-// https://www.iana.org/domains/root/db/xn--mgbaakc7dvf.html
-اتصالات
-
 // xn--mgbab2bd : CORE Association
 // https://www.iana.org/domains/root/db/xn--mgbab2bd.html
 بازار
@@ -11345,11 +11313,78 @@ myamaze.net
 // Submitted by AWS Security <psl-maintainers@amazon.com>
 // Subsections of Amazon/subsidiaries will appear until "concludes" tag
 
+// Amazon API Gateway
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 4d863337-ff98-4501-a6f2-361eba8445d6
+execute-api.cn-north-1.amazonaws.com.cn
+execute-api.cn-northwest-1.amazonaws.com.cn
+execute-api.af-south-1.amazonaws.com
+execute-api.ap-east-1.amazonaws.com
+execute-api.ap-northeast-1.amazonaws.com
+execute-api.ap-northeast-2.amazonaws.com
+execute-api.ap-northeast-3.amazonaws.com
+execute-api.ap-south-1.amazonaws.com
+execute-api.ap-south-2.amazonaws.com
+execute-api.ap-southeast-1.amazonaws.com
+execute-api.ap-southeast-2.amazonaws.com
+execute-api.ap-southeast-3.amazonaws.com
+execute-api.ap-southeast-4.amazonaws.com
+execute-api.ca-central-1.amazonaws.com
+execute-api.eu-central-1.amazonaws.com
+execute-api.eu-central-2.amazonaws.com
+execute-api.eu-north-1.amazonaws.com
+execute-api.eu-south-1.amazonaws.com
+execute-api.eu-south-2.amazonaws.com
+execute-api.eu-west-1.amazonaws.com
+execute-api.eu-west-2.amazonaws.com
+execute-api.eu-west-3.amazonaws.com
+execute-api.il-central-1.amazonaws.com
+execute-api.me-central-1.amazonaws.com
+execute-api.me-south-1.amazonaws.com
+execute-api.sa-east-1.amazonaws.com
+execute-api.us-east-1.amazonaws.com
+execute-api.us-east-2.amazonaws.com
+execute-api.us-gov-east-1.amazonaws.com
+execute-api.us-gov-west-1.amazonaws.com
+execute-api.us-west-1.amazonaws.com
+execute-api.us-west-2.amazonaws.com
+
 // Amazon CloudFront
 // Submitted by Donavan Miller <donavanm@amazon.com>
 // Reference: 54144616-fd49-4435-8535-19c6a601bdb3
 cloudfront.net
 
+// Amazon Cognito
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 7bee1013-f456-47df-bfe8-03c78d946d61
+auth.af-south-1.amazoncognito.com
+auth.ap-northeast-1.amazoncognito.com
+auth.ap-northeast-2.amazoncognito.com
+auth.ap-northeast-3.amazoncognito.com
+auth.ap-south-1.amazoncognito.com
+auth.ap-southeast-1.amazoncognito.com
+auth.ap-southeast-2.amazoncognito.com
+auth.ap-southeast-3.amazoncognito.com
+auth.ca-central-1.amazoncognito.com
+auth.eu-central-1.amazoncognito.com
+auth.eu-north-1.amazoncognito.com
+auth.eu-south-1.amazoncognito.com
+auth.eu-west-1.amazoncognito.com
+auth.eu-west-2.amazoncognito.com
+auth.eu-west-3.amazoncognito.com
+auth.il-central-1.amazoncognito.com
+auth.me-south-1.amazoncognito.com
+auth.sa-east-1.amazoncognito.com
+auth.us-east-1.amazoncognito.com
+auth-fips.us-east-1.amazoncognito.com
+auth.us-east-2.amazoncognito.com
+auth-fips.us-east-2.amazoncognito.com
+auth-fips.us-gov-west-1.amazoncognito.com
+auth.us-west-1.amazoncognito.com
+auth-fips.us-west-1.amazoncognito.com
+auth.us-west-2.amazoncognito.com
+auth-fips.us-west-2.amazoncognito.com
+
 // Amazon EC2
 // Submitted by Luke Wells <psl-maintainers@amazon.com>
 // Reference: 4c38fa71-58ac-4768-99e5-689c1767e537
@@ -11358,47 +11393,307 @@ cloudfront.net
 *.compute.amazonaws.com.cn
 us-east-1.amazonaws.com
 
+// Amazon EMR
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 597f3f8e-9283-4e48-8e32-7ee25a1ff6ab
+emrappui-prod.cn-north-1.amazonaws.com.cn
+emrnotebooks-prod.cn-north-1.amazonaws.com.cn
+emrstudio-prod.cn-north-1.amazonaws.com.cn
+emrappui-prod.cn-northwest-1.amazonaws.com.cn
+emrnotebooks-prod.cn-northwest-1.amazonaws.com.cn
+emrstudio-prod.cn-northwest-1.amazonaws.com.cn
+emrappui-prod.af-south-1.amazonaws.com
+emrnotebooks-prod.af-south-1.amazonaws.com
+emrstudio-prod.af-south-1.amazonaws.com
+emrappui-prod.ap-east-1.amazonaws.com
+emrnotebooks-prod.ap-east-1.amazonaws.com
+emrstudio-prod.ap-east-1.amazonaws.com
+emrappui-prod.ap-northeast-1.amazonaws.com
+emrnotebooks-prod.ap-northeast-1.amazonaws.com
+emrstudio-prod.ap-northeast-1.amazonaws.com
+emrappui-prod.ap-northeast-2.amazonaws.com
+emrnotebooks-prod.ap-northeast-2.amazonaws.com
+emrstudio-prod.ap-northeast-2.amazonaws.com
+emrappui-prod.ap-northeast-3.amazonaws.com
+emrnotebooks-prod.ap-northeast-3.amazonaws.com
+emrstudio-prod.ap-northeast-3.amazonaws.com
+emrappui-prod.ap-south-1.amazonaws.com
+emrnotebooks-prod.ap-south-1.amazonaws.com
+emrstudio-prod.ap-south-1.amazonaws.com
+emrappui-prod.ap-southeast-1.amazonaws.com
+emrnotebooks-prod.ap-southeast-1.amazonaws.com
+emrstudio-prod.ap-southeast-1.amazonaws.com
+emrappui-prod.ap-southeast-2.amazonaws.com
+emrnotebooks-prod.ap-southeast-2.amazonaws.com
+emrstudio-prod.ap-southeast-2.amazonaws.com
+emrappui-prod.ap-southeast-3.amazonaws.com
+emrnotebooks-prod.ap-southeast-3.amazonaws.com
+emrstudio-prod.ap-southeast-3.amazonaws.com
+emrappui-prod.ca-central-1.amazonaws.com
+emrnotebooks-prod.ca-central-1.amazonaws.com
+emrstudio-prod.ca-central-1.amazonaws.com
+emrappui-prod.eu-central-1.amazonaws.com
+emrnotebooks-prod.eu-central-1.amazonaws.com
+emrstudio-prod.eu-central-1.amazonaws.com
+emrappui-prod.eu-north-1.amazonaws.com
+emrnotebooks-prod.eu-north-1.amazonaws.com
+emrstudio-prod.eu-north-1.amazonaws.com
+emrappui-prod.eu-south-1.amazonaws.com
+emrnotebooks-prod.eu-south-1.amazonaws.com
+emrstudio-prod.eu-south-1.amazonaws.com
+emrappui-prod.eu-west-1.amazonaws.com
+emrnotebooks-prod.eu-west-1.amazonaws.com
+emrstudio-prod.eu-west-1.amazonaws.com
+emrappui-prod.eu-west-2.amazonaws.com
+emrnotebooks-prod.eu-west-2.amazonaws.com
+emrstudio-prod.eu-west-2.amazonaws.com
+emrappui-prod.eu-west-3.amazonaws.com
+emrnotebooks-prod.eu-west-3.amazonaws.com
+emrstudio-prod.eu-west-3.amazonaws.com
+emrappui-prod.me-central-1.amazonaws.com
+emrnotebooks-prod.me-central-1.amazonaws.com
+emrstudio-prod.me-central-1.amazonaws.com
+emrappui-prod.me-south-1.amazonaws.com
+emrnotebooks-prod.me-south-1.amazonaws.com
+emrstudio-prod.me-south-1.amazonaws.com
+emrappui-prod.sa-east-1.amazonaws.com
+emrnotebooks-prod.sa-east-1.amazonaws.com
+emrstudio-prod.sa-east-1.amazonaws.com
+emrappui-prod.us-east-1.amazonaws.com
+emrnotebooks-prod.us-east-1.amazonaws.com
+emrstudio-prod.us-east-1.amazonaws.com
+emrappui-prod.us-east-2.amazonaws.com
+emrnotebooks-prod.us-east-2.amazonaws.com
+emrstudio-prod.us-east-2.amazonaws.com
+emrappui-prod.us-gov-east-1.amazonaws.com
+emrnotebooks-prod.us-gov-east-1.amazonaws.com
+emrstudio-prod.us-gov-east-1.amazonaws.com
+emrappui-prod.us-gov-west-1.amazonaws.com
+emrnotebooks-prod.us-gov-west-1.amazonaws.com
+emrstudio-prod.us-gov-west-1.amazonaws.com
+emrappui-prod.us-west-1.amazonaws.com
+emrnotebooks-prod.us-west-1.amazonaws.com
+emrstudio-prod.us-west-1.amazonaws.com
+emrappui-prod.us-west-2.amazonaws.com
+emrnotebooks-prod.us-west-2.amazonaws.com
+emrstudio-prod.us-west-2.amazonaws.com
+
+// Amazon Managed Workflows for Apache Airflow
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 4ab55e6f-90c0-4a8d-b6a0-52ca5dbb1c2e
+*.cn-north-1.airflow.amazonaws.com.cn
+*.cn-northwest-1.airflow.amazonaws.com.cn
+*.ap-northeast-1.airflow.amazonaws.com
+*.ap-northeast-2.airflow.amazonaws.com
+*.ap-south-1.airflow.amazonaws.com
+*.ap-southeast-1.airflow.amazonaws.com
+*.ap-southeast-2.airflow.amazonaws.com
+*.ca-central-1.airflow.amazonaws.com
+*.eu-central-1.airflow.amazonaws.com
+*.eu-north-1.airflow.amazonaws.com
+*.eu-west-1.airflow.amazonaws.com
+*.eu-west-2.airflow.amazonaws.com
+*.eu-west-3.airflow.amazonaws.com
+*.sa-east-1.airflow.amazonaws.com
+*.us-east-1.airflow.amazonaws.com
+*.us-east-2.airflow.amazonaws.com
+*.us-west-2.airflow.amazonaws.com
+
 // Amazon S3
-// Submitted by Luke Wells <psl-maintainers@amazon.com>
-// Reference: d068bd97-f0a9-4838-a6d8-954b622ef4ae
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 0e801048-08f2-4064-9cb8-e7373e0b57f4
+s3.dualstack.cn-north-1.amazonaws.com.cn
+s3-accesspoint.dualstack.cn-north-1.amazonaws.com.cn
+s3-website.dualstack.cn-north-1.amazonaws.com.cn
 s3.cn-north-1.amazonaws.com.cn
+s3-accesspoint.cn-north-1.amazonaws.com.cn
+s3-deprecated.cn-north-1.amazonaws.com.cn
+s3-object-lambda.cn-north-1.amazonaws.com.cn
+s3-website.cn-north-1.amazonaws.com.cn
+s3.dualstack.cn-northwest-1.amazonaws.com.cn
+s3-accesspoint.dualstack.cn-northwest-1.amazonaws.com.cn
+s3.cn-northwest-1.amazonaws.com.cn
+s3-accesspoint.cn-northwest-1.amazonaws.com.cn
+s3-object-lambda.cn-northwest-1.amazonaws.com.cn
+s3-website.cn-northwest-1.amazonaws.com.cn
+s3.dualstack.af-south-1.amazonaws.com
+s3-accesspoint.dualstack.af-south-1.amazonaws.com
+s3-website.dualstack.af-south-1.amazonaws.com
+s3.af-south-1.amazonaws.com
+s3-accesspoint.af-south-1.amazonaws.com
+s3-object-lambda.af-south-1.amazonaws.com
+s3-website.af-south-1.amazonaws.com
+s3.dualstack.ap-east-1.amazonaws.com
+s3-accesspoint.dualstack.ap-east-1.amazonaws.com
+s3.ap-east-1.amazonaws.com
+s3-accesspoint.ap-east-1.amazonaws.com
+s3-object-lambda.ap-east-1.amazonaws.com
+s3-website.ap-east-1.amazonaws.com
 s3.dualstack.ap-northeast-1.amazonaws.com
+s3-accesspoint.dualstack.ap-northeast-1.amazonaws.com
+s3-website.dualstack.ap-northeast-1.amazonaws.com
+s3.ap-northeast-1.amazonaws.com
+s3-accesspoint.ap-northeast-1.amazonaws.com
+s3-object-lambda.ap-northeast-1.amazonaws.com
+s3-website.ap-northeast-1.amazonaws.com
 s3.dualstack.ap-northeast-2.amazonaws.com
+s3-accesspoint.dualstack.ap-northeast-2.amazonaws.com
+s3-website.dualstack.ap-northeast-2.amazonaws.com
 s3.ap-northeast-2.amazonaws.com
+s3-accesspoint.ap-northeast-2.amazonaws.com
+s3-object-lambda.ap-northeast-2.amazonaws.com
 s3-website.ap-northeast-2.amazonaws.com
+s3.dualstack.ap-northeast-3.amazonaws.com
+s3-accesspoint.dualstack.ap-northeast-3.amazonaws.com
+s3-website.dualstack.ap-northeast-3.amazonaws.com
+s3.ap-northeast-3.amazonaws.com
+s3-accesspoint.ap-northeast-3.amazonaws.com
+s3-object-lambda.ap-northeast-3.amazonaws.com
+s3-website.ap-northeast-3.amazonaws.com
 s3.dualstack.ap-south-1.amazonaws.com
+s3-accesspoint.dualstack.ap-south-1.amazonaws.com
+s3-website.dualstack.ap-south-1.amazonaws.com
 s3.ap-south-1.amazonaws.com
+s3-accesspoint.ap-south-1.amazonaws.com
+s3-object-lambda.ap-south-1.amazonaws.com
 s3-website.ap-south-1.amazonaws.com
+s3.dualstack.ap-south-2.amazonaws.com
+s3-accesspoint.dualstack.ap-south-2.amazonaws.com
+s3.ap-south-2.amazonaws.com
+s3-accesspoint.ap-south-2.amazonaws.com
+s3-object-lambda.ap-south-2.amazonaws.com
+s3-website.ap-south-2.amazonaws.com
 s3.dualstack.ap-southeast-1.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-1.amazonaws.com
+s3-website.dualstack.ap-southeast-1.amazonaws.com
+s3.ap-southeast-1.amazonaws.com
+s3-accesspoint.ap-southeast-1.amazonaws.com
+s3-object-lambda.ap-southeast-1.amazonaws.com
+s3-website.ap-southeast-1.amazonaws.com
 s3.dualstack.ap-southeast-2.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-2.amazonaws.com
+s3-website.dualstack.ap-southeast-2.amazonaws.com
+s3.ap-southeast-2.amazonaws.com
+s3-accesspoint.ap-southeast-2.amazonaws.com
+s3-object-lambda.ap-southeast-2.amazonaws.com
+s3-website.ap-southeast-2.amazonaws.com
+s3.dualstack.ap-southeast-3.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-3.amazonaws.com
+s3.ap-southeast-3.amazonaws.com
+s3-accesspoint.ap-southeast-3.amazonaws.com
+s3-object-lambda.ap-southeast-3.amazonaws.com
+s3-website.ap-southeast-3.amazonaws.com
+s3.dualstack.ap-southeast-4.amazonaws.com
+s3-accesspoint.dualstack.ap-southeast-4.amazonaws.com
+s3.ap-southeast-4.amazonaws.com
+s3-accesspoint.ap-southeast-4.amazonaws.com
+s3-object-lambda.ap-southeast-4.amazonaws.com
+s3-website.ap-southeast-4.amazonaws.com
 s3.dualstack.ca-central-1.amazonaws.com
+s3-accesspoint.dualstack.ca-central-1.amazonaws.com
+s3-accesspoint-fips.dualstack.ca-central-1.amazonaws.com
+s3-fips.dualstack.ca-central-1.amazonaws.com
+s3-website.dualstack.ca-central-1.amazonaws.com
 s3.ca-central-1.amazonaws.com
+s3-accesspoint.ca-central-1.amazonaws.com
+s3-accesspoint-fips.ca-central-1.amazonaws.com
+s3-fips.ca-central-1.amazonaws.com
+s3-object-lambda.ca-central-1.amazonaws.com
 s3-website.ca-central-1.amazonaws.com
 s3.dualstack.eu-central-1.amazonaws.com
+s3-accesspoint.dualstack.eu-central-1.amazonaws.com
+s3-website.dualstack.eu-central-1.amazonaws.com
 s3.eu-central-1.amazonaws.com
+s3-accesspoint.eu-central-1.amazonaws.com
+s3-object-lambda.eu-central-1.amazonaws.com
 s3-website.eu-central-1.amazonaws.com
+s3.dualstack.eu-central-2.amazonaws.com
+s3-accesspoint.dualstack.eu-central-2.amazonaws.com
+s3.eu-central-2.amazonaws.com
+s3-accesspoint.eu-central-2.amazonaws.com
+s3-object-lambda.eu-central-2.amazonaws.com
+s3-website.eu-central-2.amazonaws.com
+s3.dualstack.eu-north-1.amazonaws.com
+s3-accesspoint.dualstack.eu-north-1.amazonaws.com
+s3.eu-north-1.amazonaws.com
+s3-accesspoint.eu-north-1.amazonaws.com
+s3-object-lambda.eu-north-1.amazonaws.com
+s3-website.eu-north-1.amazonaws.com
+s3.dualstack.eu-south-1.amazonaws.com
+s3-accesspoint.dualstack.eu-south-1.amazonaws.com
+s3-website.dualstack.eu-south-1.amazonaws.com
+s3.eu-south-1.amazonaws.com
+s3-accesspoint.eu-south-1.amazonaws.com
+s3-object-lambda.eu-south-1.amazonaws.com
+s3-website.eu-south-1.amazonaws.com
+s3.dualstack.eu-south-2.amazonaws.com
+s3-accesspoint.dualstack.eu-south-2.amazonaws.com
+s3.eu-south-2.amazonaws.com
+s3-accesspoint.eu-south-2.amazonaws.com
+s3-object-lambda.eu-south-2.amazonaws.com
+s3-website.eu-south-2.amazonaws.com
 s3.dualstack.eu-west-1.amazonaws.com
+s3-accesspoint.dualstack.eu-west-1.amazonaws.com
+s3-website.dualstack.eu-west-1.amazonaws.com
+s3.eu-west-1.amazonaws.com
+s3-accesspoint.eu-west-1.amazonaws.com
+s3-deprecated.eu-west-1.amazonaws.com
+s3-object-lambda.eu-west-1.amazonaws.com
+s3-website.eu-west-1.amazonaws.com
 s3.dualstack.eu-west-2.amazonaws.com
+s3-accesspoint.dualstack.eu-west-2.amazonaws.com
 s3.eu-west-2.amazonaws.com
+s3-accesspoint.eu-west-2.amazonaws.com
+s3-object-lambda.eu-west-2.amazonaws.com
 s3-website.eu-west-2.amazonaws.com
 s3.dualstack.eu-west-3.amazonaws.com
+s3-accesspoint.dualstack.eu-west-3.amazonaws.com
+s3-website.dualstack.eu-west-3.amazonaws.com
 s3.eu-west-3.amazonaws.com
+s3-accesspoint.eu-west-3.amazonaws.com
+s3-object-lambda.eu-west-3.amazonaws.com
 s3-website.eu-west-3.amazonaws.com
+s3.dualstack.il-central-1.amazonaws.com
+s3-accesspoint.dualstack.il-central-1.amazonaws.com
+s3.il-central-1.amazonaws.com
+s3-accesspoint.il-central-1.amazonaws.com
+s3-object-lambda.il-central-1.amazonaws.com
+s3-website.il-central-1.amazonaws.com
+s3.dualstack.me-central-1.amazonaws.com
+s3-accesspoint.dualstack.me-central-1.amazonaws.com
+s3.me-central-1.amazonaws.com
+s3-accesspoint.me-central-1.amazonaws.com
+s3-object-lambda.me-central-1.amazonaws.com
+s3-website.me-central-1.amazonaws.com
+s3.dualstack.me-south-1.amazonaws.com
+s3-accesspoint.dualstack.me-south-1.amazonaws.com
+s3.me-south-1.amazonaws.com
+s3-accesspoint.me-south-1.amazonaws.com
+s3-object-lambda.me-south-1.amazonaws.com
+s3-website.me-south-1.amazonaws.com
 s3.amazonaws.com
+s3-1.amazonaws.com
+s3-ap-east-1.amazonaws.com
 s3-ap-northeast-1.amazonaws.com
 s3-ap-northeast-2.amazonaws.com
+s3-ap-northeast-3.amazonaws.com
 s3-ap-south-1.amazonaws.com
 s3-ap-southeast-1.amazonaws.com
 s3-ap-southeast-2.amazonaws.com
 s3-ca-central-1.amazonaws.com
 s3-eu-central-1.amazonaws.com
+s3-eu-north-1.amazonaws.com
 s3-eu-west-1.amazonaws.com
 s3-eu-west-2.amazonaws.com
 s3-eu-west-3.amazonaws.com
 s3-external-1.amazonaws.com
+s3-fips-us-gov-east-1.amazonaws.com
 s3-fips-us-gov-west-1.amazonaws.com
+mrap.accesspoint.s3-global.amazonaws.com
+s3-me-south-1.amazonaws.com
 s3-sa-east-1.amazonaws.com
 s3-us-east-2.amazonaws.com
+s3-us-gov-east-1.amazonaws.com
 s3-us-gov-west-1.amazonaws.com
 s3-us-west-1.amazonaws.com
 s3-us-west-2.amazonaws.com
@@ -11408,23 +11703,182 @@ s3-website-ap-southeast-2.amazonaws.com
 s3-website-eu-west-1.amazonaws.com
 s3-website-sa-east-1.amazonaws.com
 s3-website-us-east-1.amazonaws.com
+s3-website-us-gov-west-1.amazonaws.com
 s3-website-us-west-1.amazonaws.com
 s3-website-us-west-2.amazonaws.com
 s3.dualstack.sa-east-1.amazonaws.com
+s3-accesspoint.dualstack.sa-east-1.amazonaws.com
+s3-website.dualstack.sa-east-1.amazonaws.com
+s3.sa-east-1.amazonaws.com
+s3-accesspoint.sa-east-1.amazonaws.com
+s3-object-lambda.sa-east-1.amazonaws.com
+s3-website.sa-east-1.amazonaws.com
 s3.dualstack.us-east-1.amazonaws.com
+s3-accesspoint.dualstack.us-east-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-east-1.amazonaws.com
+s3-fips.dualstack.us-east-1.amazonaws.com
+s3-website.dualstack.us-east-1.amazonaws.com
+s3.us-east-1.amazonaws.com
+s3-accesspoint.us-east-1.amazonaws.com
+s3-accesspoint-fips.us-east-1.amazonaws.com
+s3-deprecated.us-east-1.amazonaws.com
+s3-fips.us-east-1.amazonaws.com
+s3-object-lambda.us-east-1.amazonaws.com
+s3-website.us-east-1.amazonaws.com
 s3.dualstack.us-east-2.amazonaws.com
+s3-accesspoint.dualstack.us-east-2.amazonaws.com
+s3-accesspoint-fips.dualstack.us-east-2.amazonaws.com
+s3-fips.dualstack.us-east-2.amazonaws.com
 s3.us-east-2.amazonaws.com
+s3-accesspoint.us-east-2.amazonaws.com
+s3-accesspoint-fips.us-east-2.amazonaws.com
+s3-deprecated.us-east-2.amazonaws.com
+s3-fips.us-east-2.amazonaws.com
+s3-object-lambda.us-east-2.amazonaws.com
 s3-website.us-east-2.amazonaws.com
+s3.dualstack.us-gov-east-1.amazonaws.com
+s3-accesspoint.dualstack.us-gov-east-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-gov-east-1.amazonaws.com
+s3-fips.dualstack.us-gov-east-1.amazonaws.com
+s3.us-gov-east-1.amazonaws.com
+s3-accesspoint.us-gov-east-1.amazonaws.com
+s3-accesspoint-fips.us-gov-east-1.amazonaws.com
+s3-fips.us-gov-east-1.amazonaws.com
+s3-object-lambda.us-gov-east-1.amazonaws.com
+s3-website.us-gov-east-1.amazonaws.com
+s3.dualstack.us-gov-west-1.amazonaws.com
+s3-accesspoint.dualstack.us-gov-west-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-gov-west-1.amazonaws.com
+s3-fips.dualstack.us-gov-west-1.amazonaws.com
+s3.us-gov-west-1.amazonaws.com
+s3-accesspoint.us-gov-west-1.amazonaws.com
+s3-accesspoint-fips.us-gov-west-1.amazonaws.com
+s3-fips.us-gov-west-1.amazonaws.com
+s3-object-lambda.us-gov-west-1.amazonaws.com
+s3-website.us-gov-west-1.amazonaws.com
+s3.dualstack.us-west-1.amazonaws.com
+s3-accesspoint.dualstack.us-west-1.amazonaws.com
+s3-accesspoint-fips.dualstack.us-west-1.amazonaws.com
+s3-fips.dualstack.us-west-1.amazonaws.com
+s3-website.dualstack.us-west-1.amazonaws.com
+s3.us-west-1.amazonaws.com
+s3-accesspoint.us-west-1.amazonaws.com
+s3-accesspoint-fips.us-west-1.amazonaws.com
+s3-fips.us-west-1.amazonaws.com
+s3-object-lambda.us-west-1.amazonaws.com
+s3-website.us-west-1.amazonaws.com
+s3.dualstack.us-west-2.amazonaws.com
+s3-accesspoint.dualstack.us-west-2.amazonaws.com
+s3-accesspoint-fips.dualstack.us-west-2.amazonaws.com
+s3-fips.dualstack.us-west-2.amazonaws.com
+s3-website.dualstack.us-west-2.amazonaws.com
+s3.us-west-2.amazonaws.com
+s3-accesspoint.us-west-2.amazonaws.com
+s3-accesspoint-fips.us-west-2.amazonaws.com
+s3-deprecated.us-west-2.amazonaws.com
+s3-fips.us-west-2.amazonaws.com
+s3-object-lambda.us-west-2.amazonaws.com
+s3-website.us-west-2.amazonaws.com
+
+// Amazon SageMaker Notebook Instances
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: fe8c9e94-5a22-486d-8750-991a3a9b13c6
+notebook.af-south-1.sagemaker.aws
+notebook.ap-east-1.sagemaker.aws
+notebook.ap-northeast-1.sagemaker.aws
+notebook.ap-northeast-2.sagemaker.aws
+notebook.ap-northeast-3.sagemaker.aws
+notebook.ap-south-1.sagemaker.aws
+notebook.ap-south-2.sagemaker.aws
+notebook.ap-southeast-1.sagemaker.aws
+notebook.ap-southeast-2.sagemaker.aws
+notebook.ap-southeast-3.sagemaker.aws
+notebook.ap-southeast-4.sagemaker.aws
+notebook.ca-central-1.sagemaker.aws
+notebook.eu-central-1.sagemaker.aws
+notebook.eu-central-2.sagemaker.aws
+notebook.eu-north-1.sagemaker.aws
+notebook.eu-south-1.sagemaker.aws
+notebook.eu-south-2.sagemaker.aws
+notebook.eu-west-1.sagemaker.aws
+notebook.eu-west-2.sagemaker.aws
+notebook.eu-west-3.sagemaker.aws
+notebook.il-central-1.sagemaker.aws
+notebook.me-central-1.sagemaker.aws
+notebook.me-south-1.sagemaker.aws
+notebook.sa-east-1.sagemaker.aws
+notebook.us-east-1.sagemaker.aws
+notebook-fips.us-east-1.sagemaker.aws
+notebook.us-east-2.sagemaker.aws
+notebook-fips.us-east-2.sagemaker.aws
+notebook.us-gov-east-1.sagemaker.aws
+notebook-fips.us-gov-east-1.sagemaker.aws
+notebook.us-gov-west-1.sagemaker.aws
+notebook-fips.us-gov-west-1.sagemaker.aws
+notebook.us-west-1.sagemaker.aws
+notebook.us-west-2.sagemaker.aws
+notebook-fips.us-west-2.sagemaker.aws
+notebook.cn-north-1.sagemaker.com.cn
+notebook.cn-northwest-1.sagemaker.com.cn
+
+// Amazon SageMaker Studio
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 057ee397-6bf8-4f20-b807-d7bc145ac980
+studio.af-south-1.sagemaker.aws
+studio.ap-east-1.sagemaker.aws
+studio.ap-northeast-1.sagemaker.aws
+studio.ap-northeast-2.sagemaker.aws
+studio.ap-northeast-3.sagemaker.aws
+studio.ap-south-1.sagemaker.aws
+studio.ap-southeast-1.sagemaker.aws
+studio.ap-southeast-2.sagemaker.aws
+studio.ap-southeast-3.sagemaker.aws
+studio.ca-central-1.sagemaker.aws
+studio.eu-central-1.sagemaker.aws
+studio.eu-north-1.sagemaker.aws
+studio.eu-south-1.sagemaker.aws
+studio.eu-west-1.sagemaker.aws
+studio.eu-west-2.sagemaker.aws
+studio.eu-west-3.sagemaker.aws
+studio.il-central-1.sagemaker.aws
+studio.me-central-1.sagemaker.aws
+studio.me-south-1.sagemaker.aws
+studio.sa-east-1.sagemaker.aws
+studio.us-east-1.sagemaker.aws
+studio.us-east-2.sagemaker.aws
+studio.us-gov-east-1.sagemaker.aws
+studio-fips.us-gov-east-1.sagemaker.aws
+studio.us-gov-west-1.sagemaker.aws
+studio-fips.us-gov-west-1.sagemaker.aws
+studio.us-west-1.sagemaker.aws
+studio.us-west-2.sagemaker.aws
+studio.cn-north-1.sagemaker.com.cn
+studio.cn-northwest-1.sagemaker.com.cn
 
 // Analytics on AWS
 // Submitted by AWS Security <psl-maintainers@amazon.com>
-// Reference: c02c3a80-f8a0-4fd2-b719-48ea8b7c28de
+// Reference: 955f9f40-a495-4e73-ae85-67b77ac9cadd
 analytics-gateway.ap-northeast-1.amazonaws.com
+analytics-gateway.ap-northeast-2.amazonaws.com
+analytics-gateway.ap-south-1.amazonaws.com
+analytics-gateway.ap-southeast-1.amazonaws.com
+analytics-gateway.ap-southeast-2.amazonaws.com
+analytics-gateway.eu-central-1.amazonaws.com
 analytics-gateway.eu-west-1.amazonaws.com
 analytics-gateway.us-east-1.amazonaws.com
 analytics-gateway.us-east-2.amazonaws.com
 analytics-gateway.us-west-2.amazonaws.com
 
+// AWS Amplify
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 5ecce854-c033-4fc4-a755-1a9916d9a9bb
+*.amplifyapp.com
+
+// AWS App Runner
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: 6828c008-ba5d-442f-ade5-48da4e7c2316
+*.awsapprunner.com
+
 // AWS Cloud9
 // Submitted by: AWS Security <psl-maintainers@amazon.com>
 // Reference: 05c44955-977c-4b57-938a-f2af92733f9f
@@ -11493,25 +11947,33 @@ vfs.cloud9.us-west-2.amazonaws.com
 webview-assets.cloud9.us-west-2.amazonaws.com
 
 // AWS Elastic Beanstalk
-// Submitted by Luke Wells <psl-maintainers@amazon.com>
-// Reference: aa202394-43a0-4857-b245-8db04549137e
+// Submitted by AWS Security <psl-maintainers@amazon.com>
+// Reference: bb5a965c-dec3-4967-aa22-e306ad064797
 cn-north-1.eb.amazonaws.com.cn
 cn-northwest-1.eb.amazonaws.com.cn
 elasticbeanstalk.com
+af-south-1.elasticbeanstalk.com
+ap-east-1.elasticbeanstalk.com
 ap-northeast-1.elasticbeanstalk.com
 ap-northeast-2.elasticbeanstalk.com
 ap-northeast-3.elasticbeanstalk.com
 ap-south-1.elasticbeanstalk.com
 ap-southeast-1.elasticbeanstalk.com
 ap-southeast-2.elasticbeanstalk.com
+ap-southeast-3.elasticbeanstalk.com
 ca-central-1.elasticbeanstalk.com
 eu-central-1.elasticbeanstalk.com
+eu-north-1.elasticbeanstalk.com
+eu-south-1.elasticbeanstalk.com
 eu-west-1.elasticbeanstalk.com
 eu-west-2.elasticbeanstalk.com
 eu-west-3.elasticbeanstalk.com
+il-central-1.elasticbeanstalk.com
+me-south-1.elasticbeanstalk.com
 sa-east-1.elasticbeanstalk.com
 us-east-1.elasticbeanstalk.com
 us-east-2.elasticbeanstalk.com
+us-gov-east-1.elasticbeanstalk.com
 us-gov-west-1.elasticbeanstalk.com
 us-west-1.elasticbeanstalk.com
 us-west-2.elasticbeanstalk.com
@@ -12727,7 +13189,7 @@ shw.io
 // Submitted by Jonathan Rudenberg <jonathan@flynn.io>
 flynnhosting.net
 
-// Forgerock : https://www.forgerock.com
+// Forgerock : https://www.forgerock.com
 // Submitted by Roderick Parr <roderick.parr@forgerock.com>
 forgeblocks.com
 id.forgerock.io
@@ -12774,7 +13236,7 @@ freemyip.com
 // Submitted by Daniel A. Maierhofer <vorstand@funkfeuer.at>
 wien.funkfeuer.at
 
-// Futureweb OG : http://www.futureweb.at
+// Futureweb GmbH : https://www.futureweb.at
 // Submitted by Andreas Schnederle-Wagner <schnederle@futureweb.at>
 *.futurecms.at
 *.ex.futurecms.at
@@ -13619,6 +14081,10 @@ azurestaticapps.net
 1.azurestaticapps.net
 2.azurestaticapps.net
 3.azurestaticapps.net
+4.azurestaticapps.net
+5.azurestaticapps.net
+6.azurestaticapps.net
+7.azurestaticapps.net
 centralus.azurestaticapps.net
 eastasia.azurestaticapps.net
 eastus2.azurestaticapps.net
@@ -13699,6 +14165,9 @@ sa.ngrok.io
 us.ngrok.io
 ngrok.pizza
 
+// Nicolaus Copernicus University in Torun - MSK TORMAN 
(https://www.man.torun.pl)
+torun.pl
+
 // Nimbus Hosting Ltd. : https://www.nimbushosting.co.uk/
 // Submitted by Nicholas Ford <nick@nimbushosting.co.uk>
 nh-serv.co.uk
diff --git a/etc/refcards/orgcard.tex b/etc/refcards/orgcard.tex
index 4b73a544e80..11e046fc0dd 100644
--- a/etc/refcards/orgcard.tex
+++ b/etc/refcards/orgcard.tex
@@ -1,5 +1,5 @@
 % Reference Card for Org Mode
-\def\orgversionnumber{9.6.11}
+\def\orgversionnumber{9.6.13}
 \def\versionyear{2023}          % latest update
 \input emacsver.tex
 
diff --git a/etc/themes/modus-operandi-tinted-theme.el 
b/etc/themes/modus-operandi-tinted-theme.el
index e66a030650c..1ef7af8f165 100644
--- a/etc/themes/modus-operandi-tinted-theme.el
+++ b/etc/themes/modus-operandi-tinted-theme.el
@@ -1,4 +1,4 @@
-;;; modus-operandi-tinted-theme.el --- Elegant, highly legible theme with a 
light ochre background -*- lexical-binding:t -*-
+;;; modus-operandi-tinted-theme.el --- Elegant, highly legible theme with a 
light ocher background -*- lexical-binding:t -*-
 
 ;; Copyright (C) 2019-2023  Free Software Foundation, Inc.
 
@@ -44,7 +44,7 @@
 
 ;;;###theme-autoload
   (deftheme modus-operandi-tinted
-    "Elegant, highly legible theme with a light ochre background.
+    "Elegant, highly legible theme with a light ocher background.
 Conforms with the highest legibility standard for color contrast
 between background and foreground in any given piece of text,
 which corresponds to a minimum contrast in relative luminance of
diff --git a/etc/themes/modus-themes.el b/etc/themes/modus-themes.el
index 34130a05515..0f7bc025b72 100644
--- a/etc/themes/modus-themes.el
+++ b/etc/themes/modus-themes.el
@@ -1535,7 +1535,7 @@ color that is combined with FG-FOR-BG."
           :foreground fg
           :weight
           ;; If we have `bold' specifically, we inherit the face of
-          ;; the same name.  This allows the user to customise that
+          ;; the same name.  This allows the user to customize that
           ;; face, such as to change its font family.
           (if (and weight (not (eq weight 'bold)))
               weight
diff --git a/exec/exec1.c b/exec/exec1.c
index d77ca8adf54..6ec4b3ecaae 100644
--- a/exec/exec1.c
+++ b/exec/exec1.c
@@ -53,7 +53,7 @@ main (int argc, char **argv)
 
       tracing_execve (argv[2], argv + 2, environ);
 
-      /* An error occured.  Exit with failure.  */
+      /* An error occurred.  Exit with failure.  */
       exit (127);
     }
   else
diff --git a/exec/loader-armeabi.s b/exec/loader-armeabi.s
index 32b2a5268d6..bee81edb326 100644
--- a/exec/loader-armeabi.s
+++ b/exec/loader-armeabi.s
@@ -200,5 +200,5 @@ timespec:
        .long 10
 
 @ Local Variables:
-@ asm-comment-char: 64
+@ asm-comment-char: ?@
 @ End:
diff --git a/exec/loader-mips64el.s b/exec/loader-mips64el.s
index f4a6f918497..c340824a6f0 100644
--- a/exec/loader-mips64el.s
+++ b/exec/loader-mips64el.s
@@ -230,5 +230,5 @@ dnl syscall                         # syscall
        .quad   10
 
 # Local Variables:
-# asm-comment-char: 35
+# asm-comment-char: ?#
 # End:
diff --git a/exec/loader-mipsel.s b/exec/loader-mipsel.s
index baba3f05a94..e1ae68af0ca 100644
--- a/exec/loader-mipsel.s
+++ b/exec/loader-mipsel.s
@@ -232,5 +232,5 @@ RESTORE()                           # restore sp
        .long   10
 
 # Local Variables:
-# asm-comment-char: 35
+# asm-comment-char: ?#
 # End:
diff --git a/exec/trace.c b/exec/trace.c
index f9deef8eb2d..ccf498f39fe 100644
--- a/exec/trace.c
+++ b/exec/trace.c
@@ -1028,7 +1028,7 @@ process_system_call (struct exec_tracee *tracee)
          break;
 
        case 1:
-         /* An error has occured; errno is set to the error.  */
+         /* An error has occurred; errno is set to the error.  */
          goto report_syscall_error;
        }
 
diff --git a/java/AndroidManifest.xml.in b/java/AndroidManifest.xml.in
index 2749f43c245..18afe945df6 100644
--- a/java/AndroidManifest.xml.in
+++ b/java/AndroidManifest.xml.in
@@ -94,7 +94,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>. -->
              android:launchMode="singleInstance"
              android:windowSoftInputMode="adjustResize"
              android:exported="true"
-             
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden">
+             
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|locale|fontScale">
       <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.DEFAULT" />
@@ -149,7 +149,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>. -->
     <activity android:name="org.gnu.emacs.EmacsMultitaskActivity"
              android:windowSoftInputMode="adjustResize"
              android:exported="true"
-             
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden"/>
+             
android:configChanges="orientation|screenSize|screenLayout|keyboardHidden|locale|fontScale"/>
 
     <activity android:autoRemoveFromRecents="true"
               android:label="Emacs options"
diff --git a/java/INSTALL b/java/INSTALL
index fb221c5e2b4..60171ada57c 100644
--- a/java/INSTALL
+++ b/java/INSTALL
@@ -167,7 +167,7 @@ than a compressed package for a newer version of Android.
 BUILDING C++ DEPENDENCIES
 
 With a new version of the NDK, dependencies containing C++ code should
-build without any futher configuration.  However, older versions
+build without any further configuration.  However, older versions
 require that you use the ``make_standalone_toolchain.py'' script in
 the NDK distribution to create a ``standalone toolchain'', and use
 that instead, in order for C++ headers to be found.
@@ -309,7 +309,7 @@ work, along with what has to be patched to make them work:
 Many of these dependencies have been migrated over to the
 ``Android.bp'' build system now used to build Android itself.
 However, the old ``Android.mk'' Makefiles are still present in older
-branches, and can be easily adapte to newer versions.
+branches, and can be easily adapted to newer versions.
 
 In addition, some Emacs dependencies provide `ndk-build' support
 themselves:
diff --git a/java/org/gnu/emacs/EmacsContextMenu.java 
b/java/org/gnu/emacs/EmacsContextMenu.java
index c415ba59c79..2652f35b545 100644
--- a/java/org/gnu/emacs/EmacsContextMenu.java
+++ b/java/org/gnu/emacs/EmacsContextMenu.java
@@ -36,7 +36,7 @@ import android.view.SubMenu;
 import android.util.Log;
 
 /* Context menu implementation.  This object is built from JNI and
-   describes a menu hiearchy.  Then, `inflate' can turn it into an
+   describes a menu hierarchy.  Then, `inflate' can turn it into an
    Android menu, which can be turned into a popup (or other kind of)
    menu.  */
 
diff --git a/java/org/gnu/emacs/EmacsInputConnection.java 
b/java/org/gnu/emacs/EmacsInputConnection.java
index 7f6331205cb..4b493dcc456 100644
--- a/java/org/gnu/emacs/EmacsInputConnection.java
+++ b/java/org/gnu/emacs/EmacsInputConnection.java
@@ -60,7 +60,7 @@ public final class EmacsInputConnection implements 
InputConnection
 
      This helps with on screen keyboard programs found in some vendor
      versions of Android, which rely on immediate updates to the point
-     position after text is commited in order to place the cursor
+     position after text is committed in order to place the cursor
      within that text.  */
 
   private static boolean syncAfterCommit;
diff --git a/java/org/gnu/emacs/EmacsOpenActivity.java 
b/java/org/gnu/emacs/EmacsOpenActivity.java
index 32a79d1a797..b4fd68146be 100644
--- a/java/org/gnu/emacs/EmacsOpenActivity.java
+++ b/java/org/gnu/emacs/EmacsOpenActivity.java
@@ -636,7 +636,7 @@ public final class EmacsOpenActivity extends Activity
                  {
                    /* This means Emacs lacks the rights to open this
                       file.  Display the error message and exit.  */
-                   displayFailureDialog ("Error openining file",
+                   displayFailureDialog ("Error opening file",
                                          exception.toString ());
                    return;
                  }
diff --git a/java/org/gnu/emacs/EmacsSafThread.java 
b/java/org/gnu/emacs/EmacsSafThread.java
index 7917e2d4880..333c3a29790 100644
--- a/java/org/gnu/emacs/EmacsSafThread.java
+++ b/java/org/gnu/emacs/EmacsSafThread.java
@@ -504,7 +504,7 @@ public final class EmacsSafThread extends HandlerThread
   cacheDirectoryFromCursor (CacheToplevel toplevel, String documentId,
                            Cursor cursor)
   {
-    CacheEntry entry, constitutent;
+    CacheEntry entry, constituent;
     int nameColumn, idColumn, typeColumn;
     String id, name, type;
     DocIdEntry idEntry;
@@ -561,8 +561,8 @@ public final class EmacsSafThread extends HandlerThread
 
            /* Otherwise, create a new cache entry comprised of its
               type.  */
-           constitutent = new CacheEntry ();
-           constitutent.type = type;
+           constituent = new CacheEntry ();
+           constituent.type = type;
            toplevel.idCache.put (documentId, entry);
          }
        catch (Exception e)
@@ -767,7 +767,7 @@ public final class EmacsSafThread extends HandlerThread
 
   private abstract class SafIntFunction
   {
-    /* The ``throws Throwable'' here is a Java idiosyncracy that tells
+    /* The ``throws Throwable'' here is a Java idiosyncrasy that tells
        the compiler to allow arbitrary error objects to be signaled
        from within this function.
 
@@ -782,7 +782,7 @@ public final class EmacsSafThread extends HandlerThread
 
   private abstract class SafObjectFunction
   {
-    /* The ``throws Throwable'' here is a Java idiosyncracy that tells
+    /* The ``throws Throwable'' here is a Java idiosyncrasy that tells
        the compiler to allow arbitrary error objects to be signaled
        from within this function.
 
@@ -1216,7 +1216,7 @@ public final class EmacsSafThread extends HandlerThread
       });
   }
 
-  /* The bulk of `statDocument'.  SIGNAL should be a cancelation
+  /* The bulk of `statDocument'.  SIGNAL should be a cancellation
      signal.  */
 
   private long[]
diff --git a/java/org/gnu/emacs/EmacsService.java 
b/java/org/gnu/emacs/EmacsService.java
index 33832505333..c71670b3e47 100644
--- a/java/org/gnu/emacs/EmacsService.java
+++ b/java/org/gnu/emacs/EmacsService.java
@@ -612,7 +612,7 @@ public final class EmacsService extends Service
          context.startService (new Intent (context,
                                            EmacsService.class));
        else
-         /* Display the permanant notification and start Emacs as a
+         /* Display the permanent notification and start Emacs as a
             foreground service.  */
          context.startForegroundService (new Intent (context,
                                                      EmacsService.class));
@@ -679,7 +679,7 @@ public final class EmacsService extends Service
            /* Display a list of programs able to send this URL.  */
            intent = Intent.createChooser (intent, "Send");
 
-           /* Apparently flags need to be set after a choser is
+           /* Apparently flags need to be set after a chooser is
               created.  */
            intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK);
          }
@@ -927,7 +927,7 @@ public final class EmacsService extends Service
 
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
       /* Since the system predates drag and drop, return this resolver
-        to avoid any unforseen difficulties.  */
+        to avoid any unforeseen difficulties.  */
       return resolver;
 
     activity = EmacsActivity.lastFocusedActivity;
@@ -947,7 +947,7 @@ public final class EmacsService extends Service
 
     if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N)
       /* Since the system predates drag and drop, return this resolver
-        to avoid any unforseen difficulties.  */
+        to avoid any unforeseen difficulties.  */
       return this;
 
     activity = EmacsActivity.lastFocusedActivity;
diff --git a/java/org/gnu/emacs/EmacsView.java 
b/java/org/gnu/emacs/EmacsView.java
index 2d53231fbf9..5795f476f63 100644
--- a/java/org/gnu/emacs/EmacsView.java
+++ b/java/org/gnu/emacs/EmacsView.java
@@ -388,7 +388,7 @@ public final class EmacsView extends ViewGroup
                && !rootWindowInsets.isVisible (WindowInsets.Type.ime ())
                /* N.B. that the keyboard is dismissed during gesture
                   navigation under Android 30, but the system is
-                  quite tempermental regarding whether the window is
+                  quite temperamental regarding whether the window is
                   focused at that point.  Ideally
                   isCurrentlyTextEditor shouldn't be reset in that
                   case, but detecting that situation appears to be
diff --git a/java/org/gnu/emacs/EmacsWindow.java 
b/java/org/gnu/emacs/EmacsWindow.java
index 7d161fdcf88..0dc4a274731 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -428,7 +428,7 @@ public final class EmacsWindow extends EmacsHandleObject
                  manager = EmacsWindowAttachmentManager.MANAGER;
 
                  /* If parent is the root window, notice that there are new
-                    children available for interested activites to pick
+                    children available for interested activities to pick
                     up.  */
                  manager.registerWindow (EmacsWindow.this);
 
@@ -644,7 +644,7 @@ public final class EmacsWindow extends EmacsHandleObject
   public void
   onKeyDown (int keyCode, KeyEvent event)
   {
-    int state, state_1;
+    int state, state_1, num_lock_flag;
     long serial;
     String characters;
 
@@ -665,13 +665,23 @@ public final class EmacsWindow extends EmacsHandleObject
 
     state = eventModifiers (event);
 
+    /* Num Lock and Scroll Lock aren't supported by systems older than
+       Android 3.0. */
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
+      num_lock_flag = (KeyEvent.META_NUM_LOCK_ON
+                      | KeyEvent.META_SCROLL_LOCK_ON);
+    else
+      num_lock_flag = 0;
+
     /* Ignore meta-state understood by Emacs for now, or key presses
        such as Ctrl+C and Meta+C will not be recognized as an ASCII
        key press event.  */
 
     state_1
       = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK
-                 | KeyEvent.META_SYM_ON | KeyEvent.META_META_MASK);
+                 | KeyEvent.META_SYM_ON | KeyEvent.META_META_MASK
+                 | num_lock_flag);
 
     synchronized (eventStrings)
       {
@@ -692,19 +702,29 @@ public final class EmacsWindow extends EmacsHandleObject
   public void
   onKeyUp (int keyCode, KeyEvent event)
   {
-    int state, state_1, unicode_char;
+    int state, state_1, unicode_char, num_lock_flag;
     long time;
 
     /* Compute the event's modifier mask.  */
     state = eventModifiers (event);
 
+    /* Num Lock and Scroll Lock aren't supported by systems older than
+       Android 3.0. */
+
+    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
+      num_lock_flag = (KeyEvent.META_NUM_LOCK_ON
+                      | KeyEvent.META_SCROLL_LOCK_ON);
+    else
+      num_lock_flag = 0;
+
     /* Ignore meta-state understood by Emacs for now, or key presses
        such as Ctrl+C and Meta+C will not be recognized as an ASCII
        key press event.  */
 
     state_1
       = state & ~(KeyEvent.META_ALT_MASK | KeyEvent.META_CTRL_MASK
-                 | KeyEvent.META_SYM_ON | KeyEvent.META_META_MASK);
+                 | KeyEvent.META_SYM_ON | KeyEvent.META_META_MASK
+                 | num_lock_flag);
 
     unicode_char = getEventUnicodeChar (event, state_1);
 
@@ -1399,7 +1419,7 @@ public final class EmacsWindow extends EmacsHandleObject
                  }
 
                /* Effect the same adjustment upon the view
-                  hiearchy.  */
+                  hierarchy.  */
 
                EmacsService.SERVICE.runOnUiThread (new Runnable () {
                    @Override
diff --git a/lisp/ChangeLog.12 b/lisp/ChangeLog.12
index 88d3a41461c..9de45ef0605 100644
--- a/lisp/ChangeLog.12
+++ b/lisp/ChangeLog.12
@@ -10678,7 +10678,7 @@
        for root variables.
 
        * progmodes/gdb-ui.el (gdb-pc-address): Rename from gdb-frame-address.
-       (gdb-frame-address): Re-use to identify frame for watch expression.
+       (gdb-frame-address): Reuse to identify frame for watch expression.
        (gdb-var-list, gdb-var-create-handler): Add frame address for root
        variables.
        (gdb-init-1, gdb-source, gdb-post-prompt)
diff --git a/lisp/ChangeLog.13 b/lisp/ChangeLog.13
index ac382e1685d..808de5d183f 100644
--- a/lisp/ChangeLog.13
+++ b/lisp/ChangeLog.13
@@ -12592,7 +12592,7 @@
 
        * textmodes/org.el (org-agenda-skip): Allow a form for
        `org-agenda-skip-function'.
-       (org-agenda-redo): Re-use local settings.
+       (org-agenda-redo): Reuse local settings.
        (org-agenda): Store local settings.
        (org-agenda-deadline-faces): New option.
        (org-agenda-deadline-face): New function.
diff --git a/lisp/ChangeLog.14 b/lisp/ChangeLog.14
index efaac2869c8..a7a028d6708 100644
--- a/lisp/ChangeLog.14
+++ b/lisp/ChangeLog.14
@@ -16505,7 +16505,7 @@
        (diary-list-entries-2): Simplify finding start of date.
        (diary-show-all-entries, make-diary-entry): Respect non-nil values of
        pop-up-frames.
-       (diary-mark-entries-1): Re-use offset in abbreviated-year case.
+       (diary-mark-entries-1): Reuse offset in abbreviated-year case.
        (mark-sexp-diary-entries): Remove superfluous call to diary-pull-attrs.
 
 2008-03-27  Dan Nicolaescu  <dann@ics.uci.edu>
@@ -17072,14 +17072,14 @@
        * calendar/cal-bahai.el (calendar-bahai-leap-year-p)
        (calendar-bahai-leap-base, calendar-bahai-from-absolute): Doc fixes.
        (calendar-absolute-from-bahai): Fix the leap-year case.
-       (calendar-bahai-from-absolute): Re-use the Gregorian month.
+       (calendar-bahai-from-absolute): Reuse the Gregorian month.
        (calendar-bahai-date-string, calendar-bahai-print-date):
        Handle pre-Bahai dates.
 
        * calendar/cal-china.el (chinese-calendar-celestial-stem)
        (chinese-calendar-terrestrial-branch): Make defcustoms.
 
-       * calendar/cal-menu.el (calendar-mouse-holidays): Re-use the title.
+       * calendar/cal-menu.el (calendar-mouse-holidays): Reuse the title.
        (calendar-mouse-view-diary-entries): Use or.
        (calendar-mouse-chinese-date): Remove unused command.
        (cal-menu-load-hook): Mark as obsolete.
diff --git a/lisp/ChangeLog.15 b/lisp/ChangeLog.15
index c6026b8b9a8..7270961abcb 100644
--- a/lisp/ChangeLog.15
+++ b/lisp/ChangeLog.15
@@ -7702,7 +7702,7 @@
 
        * finder.el: Load finder-inf using `require'.
        (finder-list-matches): Sorting by status is now the default.
-       (finder-compile-keywords): Simpify printing.
+       (finder-compile-keywords): Simplify printing.
 
 2010-08-30  Stefan Monnier  <monnier@iro.umontreal.ca>
 
diff --git a/lisp/ChangeLog.16 b/lisp/ChangeLog.16
index 39649ec8ae0..f0e5178b498 100644
--- a/lisp/ChangeLog.16
+++ b/lisp/ChangeLog.16
@@ -1770,7 +1770,7 @@
        (jit-lock--debug-fontifying): New var.
        (jit-lock--debug-fontify): New function.
        * subr.el (condition-case-unless-debug): Don't prevent catching the
-       error, just let the debbugger run.
+       error, just let the debugger run.
        * emacs-lisp/timer.el (timer-event-handler): Don't prevent debugging
        timer code and don't drop errors silently.
 
@@ -4784,7 +4784,7 @@
        Convert to defcustom.
        (gdb-get-source-file): Don't bind pop-up-windows.
 
-       * progmodes/gud.el (gud-display-line): Don't specially re-use
+       * progmodes/gud.el (gud-display-line): Don't specially reuse
        other frames for the gdb-mi case (Bug#12648).
 
 2012-10-18  Stefan Monnier  <monnier@iro.umontreal.ca>
diff --git a/lisp/ChangeLog.17 b/lisp/ChangeLog.17
index 19b8e1e28eb..359934ab961 100644
--- a/lisp/ChangeLog.17
+++ b/lisp/ChangeLog.17
@@ -4339,7 +4339,7 @@
        (verilog-beg-of-statement-1, verilog-at-constraint-p):
        Fix hanging with many curly-bracket pairs, bug663.
        (verilog-do-indent): Fix electric tab deleting form-feeds.
-       Note caused by indent-line-to deleting tabls pre 24.5.
+       Note caused by indent-line-to deleting tables pre 24.5.
        (verilog-auto-output, verilog-auto-input, verilog-auto-inout)
        (verilog-auto-inout-module, verilog-auto-inout-in): Doc fixes.
        (verilog-read-always-signals, verilog-auto-sense-sigs)
diff --git a/lisp/ChangeLog.7 b/lisp/ChangeLog.7
index 17464042b76..b99bc10e0c4 100644
--- a/lisp/ChangeLog.7
+++ b/lisp/ChangeLog.7
@@ -5232,7 +5232,7 @@
 
 1998-03-29  Ralph Schleicher  <rs@purple.UL.BaWue.DE>
 
-       * battery.el (battery-linux-proc-apm): Re-use the temporary
+       * battery.el (battery-linux-proc-apm): Reuse the temporary
        buffer.
 
        * battery.el (battery-insert-file-contents): Disable code
diff --git a/lisp/button.el b/lisp/button.el
index ed11c9583d8..4d66fc57d87 100644
--- a/lisp/button.el
+++ b/lisp/button.el
@@ -494,7 +494,7 @@ pushing a button, use the `button-describe' command."
                (button-activate str t)
               (if (eq (car-safe pos) 'touchscreen-down)
                   ;; If touch-screen-track tap returns nil, then the
-                  ;; tap was cancelled.
+                  ;; tap was canceled.
                   (when (touch-screen-track-tap pos nil nil t)
                     (push-button (posn-point posn) t))
                 (push-button (posn-point posn) t))))))
diff --git a/lisp/calc/calc.el b/lisp/calc/calc.el
index 41aeb17c252..50623218701 100644
--- a/lisp/calc/calc.el
+++ b/lisp/calc/calc.el
@@ -1285,6 +1285,8 @@ the trail buffer."
           (setq calc-trail-buffer nil)
           t))))
 
+(defvar touch-screen-display-keyboard)
+
 (defun calc-mode ()
   "Calculator major mode.
 
diff --git a/lisp/cedet/ChangeLog.1 b/lisp/cedet/ChangeLog.1
index 5242c73062b..ce6544dcc88 100644
--- a/lisp/cedet/ChangeLog.1
+++ b/lisp/cedet/ChangeLog.1
@@ -1515,7 +1515,7 @@
        * semantic/complete.el (semantic-complete-post-command-hook):
        Exit completion when user has deleted all characters from the prefix.
        (semantic-displayor-focus-request): Return to previous window when
-       focussing tags.
+       focusing tags.
 
        * semantic/db-el.el (semanticdb-normalize-one-tag): Make obsolete.
        (semanticdb-elisp-sym->tag): Use help-function-arglist instead.
diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el
index 84040b572bc..64fd2901a49 100644
--- a/lisp/cedet/semantic/complete.el
+++ b/lisp/cedet/semantic/complete.el
@@ -1046,7 +1046,7 @@ Output must be in semanticdb Find result format."
                     (and last-prefix (string-prefix-p last-prefix prefix t)))
                 ;; We have the same prefix, or last-prefix is a
                 ;; substring of the of new prefix, in which case we are
-                ;; refining our symbol so just re-use cache.
+                ;; refining our symbol so just reuse cache.
                 (oref obj last-all-completions))
                ((and last-prefix
                      (> (length prefix) 1)
diff --git a/lisp/cedet/srecode/extract.el b/lisp/cedet/srecode/extract.el
index 4eb7632b721..7e74746f1da 100644
--- a/lisp/cedet/srecode/extract.el
+++ b/lisp/cedet/srecode/extract.el
@@ -33,7 +33,7 @@
 ;; or deep template calls can be extracted.
 ;;
 ;; This code was specifically written for srecode-document, which
-;; wants to extract user written text, and re-use it in a reformatted
+;; wants to extract user written text, and reuse it in a reformatted
 ;; comment.
 
 (require 'srecode)
diff --git a/lisp/cedet/srecode/srt-mode.el b/lisp/cedet/srecode/srt-mode.el
index 6bd416c5690..30509298ddc 100644
--- a/lisp/cedet/srecode/srt-mode.el
+++ b/lisp/cedet/srecode/srt-mode.el
@@ -420,7 +420,7 @@ Moves to the end of one named section."
              (when (string= (car (car subdicts)) name)
                (setq res (cdr (car subdicts))))
              (setq subdicts (cdr subdicts)))
-           ;; Pre-pend our global vars.
+           ;; Prepend our global vars.
            (append global res))
        ;; If we aren't in a subsection, just do the global variables
        global
diff --git a/lisp/completion-preview.el b/lisp/completion-preview.el
index 1d5f1253702..2ed2e5dd001 100644
--- a/lisp/completion-preview.el
+++ b/lisp/completion-preview.el
@@ -189,10 +189,24 @@ Completion Preview mode avoids updating the preview after 
these commands.")
   "Return property PROP of the completion preview overlay."
   (overlay-get completion-preview--overlay prop))
 
+(defun completion-preview--window-selection-change (window)
+  "Hide completion preview in WINDOW after switching to another window.
+Completion Preview mode adds this function to
+`window-selection-change-functions', which see."
+  (unless (or (eq window (selected-window))
+              (eq window (minibuffer-selected-window)))
+    (with-current-buffer (window-buffer window)
+      (completion-preview-active-mode -1))))
+
 (define-minor-mode completion-preview-active-mode
   "Mode for when the completion preview is shown."
   :interactive nil
-  (unless completion-preview-active-mode (completion-preview-hide)))
+  (if completion-preview-active-mode
+      (add-hook 'window-selection-change-functions
+                #'completion-preview--window-selection-change nil t)
+    (remove-hook 'window-selection-change-functions
+                 #'completion-preview--window-selection-change t)
+    (completion-preview-hide)))
 
 (defun completion-preview--try-table (table beg end props)
   "Check TABLE for a completion matching the text between BEG and END.
diff --git a/lisp/desktop.el b/lisp/desktop.el
index f096f13ab80..0b27dde1d70 100644
--- a/lisp/desktop.el
+++ b/lisp/desktop.el
@@ -293,7 +293,7 @@ May be used to show a dired buffer."
   :version "22.1")
 
 (defcustom desktop-not-loaded-hook nil
-  "Normal hook run when the user declines to re-use a desktop file.
+  "Normal hook run when the user declines to reuse a desktop file.
 Run in the directory in which the desktop file was found.
 May be used to deal with accidental multiple Emacs jobs."
   :type 'hook
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 1a17ed749e8..44e9ae3701e 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -1367,7 +1367,8 @@ after adding own commands to the composite list."
   (let* ((xdg-mime (when (executable-find "xdg-mime")
                      (string-trim-right
                       (shell-command-to-string
-                       (concat "xdg-mime query filetype " (car files))))))
+                       (concat "xdg-mime query filetype "
+                               (shell-quote-argument (car files)))))))
          (xdg-mime-apps (unless (string-empty-p xdg-mime)
                           (xdg-mime-apps xdg-mime)))
          (xdg-commands
@@ -1401,6 +1402,42 @@ after adding own commands to the composite list."
   "Populate COMMANDS by the `open' command."
   (append (ensure-list shell-command-guess-open) commands))
 
+(declare-function w32-shell-execute "w32fns.c")
+
+(defun dired-do-open (&optional arg)
+  "Open all marked (or next ARG) files using an external program.
+This \"opens\" the file(s) using the external command that is most
+appropriate for the file(s) according to the system conventions.
+If files are marked, run the command on each marked file.  Otherwise,
+run it on the next ARG files, or on the file at mouse-click, or on the
+file at point.  The appropriate command to \"open\" a file on each
+system is determined by `shell-command-guess-open'."
+  (interactive "P" dired-mode)
+  (let ((files (if (mouse-event-p last-nonmenu-event)
+                   (save-excursion
+                     (mouse-set-point last-nonmenu-event)
+                     (dired-get-marked-files nil arg))
+                 (dired-get-marked-files nil arg)))
+        (command shell-command-guess-open))
+    (when (and (memq system-type '(windows-nt))
+               (equal command "start"))
+      (setq command "open"))
+    (when command
+      (dolist (file files)
+        (cond
+         ((memq system-type '(gnu/linux))
+          (call-process command nil 0 nil file))
+         ((memq system-type '(ms-dos))
+          (shell-command (concat command " " (shell-quote-argument file))))
+         ((memq system-type '(windows-nt))
+          (w32-shell-execute command (convert-standard-filename file)))
+         ((memq system-type '(cygwin))
+          (call-process command nil nil nil file))
+         ((memq system-type '(darwin))
+          (start-process (concat command " " file) nil command file))
+         (t
+          (error "Open not supported on this system")))))))
+
 
 ;;; Commands that delete or redisplay part of the dired buffer
 
diff --git a/lisp/dired-x.el b/lisp/dired-x.el
index 04b3c783084..e094c0b4ca7 100644
--- a/lisp/dired-x.el
+++ b/lisp/dired-x.el
@@ -613,7 +613,8 @@ you can relist single subdirs using \\[dired-do-redisplay]."
       (insert "  "
              (directory-file-name (file-name-directory default-directory))
              ":\n"))
-  (dired-mode dirname (or switches dired-listing-switches))
+  (dired-mode
+   dirname (or switches (connection-local-value dired-listing-switches)))
   (setq mode-name "Virtual Dired"
         revert-buffer-function 'dired-virtual-revert
         dired-subdir-alist nil)
diff --git a/lisp/dired.el b/lisp/dired.el
index 97645c731c8..33e38ed2c1c 100644
--- a/lisp/dired.el
+++ b/lisp/dired.el
@@ -75,7 +75,9 @@ each option.
 
 On systems such as MS-DOS and MS-Windows, which use `ls' emulation in Lisp,
 some of the `ls' switches are not supported; see the doc string of
-`insert-directory' in `ls-lisp.el' for more details."
+`insert-directory' in `ls-lisp.el' for more details.
+
+For remote Dired buffers, this option supports connection-local values."
   :type 'string
   :group 'dired)
 
@@ -1383,7 +1385,8 @@ The return value is the target column for the file names."
                ;; is passed in directory name syntax
                ;; if it was the name of a directory at all.
                (file-name-directory dirname)))
-      (or switches (setq switches dired-listing-switches))
+      (or switches
+          (setq switches (connection-local-value dired-listing-switches)))
       (if mode (funcall mode)
         (dired-mode dir-or-list switches))
       ;; default-directory and dired-actual-switches are set now
@@ -2591,6 +2594,9 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
     ["Delete Image Tag..." image-dired-delete-tag
      :help "Delete image tag from current or marked files"]))
 
+(declare-function shell-command-guess "dired-aux" (files))
+(defvar shell-command-guess-open)
+
 (defun dired-context-menu (menu click)
   "Populate MENU with Dired mode commands at CLICK."
   (when (mouse-posn-property (event-start click) 'dired-filename)
@@ -2606,6 +2612,9 @@ Do so according to the former subdir alist 
OLD-SUBDIR-ALIST."
            :help "Edit file at mouse click"]
           ["Find in Other Window" dired-mouse-find-file-other-window
            :help "Edit file at mouse click in other window"]
+          ,@(when shell-command-guess-open
+              '(["Open" dired-do-open
+                 :help "Open externally"]))
           ,@(when commands
               (list (cons "Open With"
                           (append
@@ -2708,7 +2717,8 @@ Keybindings:
        (expand-file-name (if (listp dired-directory)
                              (car dired-directory)
                            dired-directory)))
-  (setq-local dired-actual-switches (or switches dired-listing-switches))
+  (setq-local dired-actual-switches
+              (or switches (connection-local-value dired-listing-switches)))
   (setq-local font-lock-defaults
               '(dired-font-lock-keywords t nil nil beginning-of-line))
   (setq-local desktop-save-buffer 'dired-desktop-buffer-misc-data)
@@ -4983,14 +4993,15 @@ Ask means pop up a menu for the user to select one of 
copy, move or link."
 
 (defun dired-desktop-save-p ()
   "Should `dired-directory' be desktop saved?"
-  (if (consp dired-directory)
-      (not (string-match-p desktop-files-not-to-save (car dired-directory)))
-    (not (string-match-p desktop-files-not-to-save dired-directory))))
+  (or (null desktop-files-not-to-save)
+      (and (stringp desktop-files-not-to-save)
+           (if (consp dired-directory)
+               (not (string-match-p desktop-files-not-to-save (car 
dired-directory)))
+             (not (string-match-p desktop-files-not-to-save 
dired-directory))))))
 
 (defun dired-desktop-buffer-misc-data (dirname)
   "Auxiliary information to be saved in desktop file."
-  (when (and (stringp desktop-files-not-to-save)
-             (dired-desktop-save-p))
+  (when (dired-desktop-save-p)
     (cons
      ;; Value of `dired-directory'.
      (if (consp dired-directory)
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index 7a61a8fce7e..5a72011c609 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -440,7 +440,7 @@ There can be multiple entries for the same NAME if it has 
several aliases.")
 
       (`(unwind-protect ,protected-expr :fun-body ,unwind-fun)
        ;; FIXME: The return value of UNWIND-FUN is never used so we
-       ;; could potentially optimise it for-effect, but we don't do
+       ;; could potentially optimize it for-effect, but we don't do
        ;; that right no.
        `(,fn ,(byte-optimize-form protected-expr for-effect)
              :fun-body ,(byte-optimize-form unwind-fun)))
@@ -973,7 +973,7 @@ There can be multiple entries for the same NAME if it has 
several aliases.")
     (list (car form) (nth 2 form) (nth 1 form)))))
 
 (defun byte-opt--nary-comparison (form)
-  "Optimise n-ary comparisons such as `=', `<' etc."
+  "Optimize n-ary comparisons such as `=', `<' etc."
   (let ((nargs (length (cdr form))))
     (cond
      ((= nargs 1)
@@ -988,7 +988,7 @@ There can be multiple entries for the same NAME if it has 
several aliases.")
         (if (memq nil (mapcar #'macroexp-copyable-p (cddr form)))
             ;; At least one arg beyond the first is non-constant non-variable:
             ;; create temporaries for all args to guard against side-effects.
-            ;; The optimiser will eliminate trivial bindings later.
+            ;; The optimizer will eliminate trivial bindings later.
             (let ((i 1))
               (dolist (arg (cdr form))
                 (let ((var (make-symbol (format "arg%d" i))))
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 674dfcc8f56..d36bb34848e 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -3568,7 +3568,7 @@ lambda-expression."
             (cond
              ((and sef (or (eq sef 'error-free)
                            byte-compile-delete-errors))
-              ;; This transform is normally done in the Lisp optimiser,
+              ;; This transform is normally done in the Lisp optimizer,
               ;; so maybe we don't need to bother about it here?
               (setq form (cons 'progn (cdr form)))
               (setq handler #'byte-compile-progn))
@@ -3605,7 +3605,7 @@ lambda-expression."
 (let ((important-return-value-fns
        '(
          ;; These functions are side-effect-free except for the
-         ;; behaviour of functions passed as argument.
+         ;; behavior of functions passed as argument.
          mapcar mapcan mapconcat
          assoc plist-get plist-member
 
@@ -4150,7 +4150,7 @@ If it is nil, then the handler is 
\"byte-compile-SYMBOL.\""
     (byte-compile-two-args
      (if (macroexp-const-p (nth 1 form))
          ;; First argument is constant: flip it so that the constant
-         ;; is last, which may allow more lapcode optimisations.
+         ;; is last, which may allow more lapcode optimizations.
          (let* ((op (car form))
                 (flipped-op (cdr (assq op '((< . >) (<= . >=)
                                             (> . <) (>= . <=) (= . =))))))
@@ -4314,7 +4314,7 @@ This function is never called when `lexical-binding' is 
nil."
            (arg2 (nth 2 form)))
        (when (and (memq (car form) '(+ *))
                   (macroexp-const-p arg1))
-         ;; Put constant argument last for better LAP optimisation.
+         ;; Put constant argument last for better LAP optimization.
          (cl-rotatef arg1 arg2))
        (byte-compile-form arg1)
        (byte-compile-form arg2)
@@ -5328,7 +5328,7 @@ FORM is used to provide location, 
`bytecomp--cus-function' and
   "Warn about common mistakes in the `defcustom' type TYPE."
   (let ((invalid-types
          '(
-           ;; Lisp type predicates, often confused with customisation types:
+           ;; Lisp type predicates, often confused with customization types:
            functionp numberp integerp fixnump natnump floatp booleanp
            characterp listp stringp consp vectorp symbolp keywordp
            hash-table-p facep
diff --git a/lisp/emacs-lisp/cl-macs.el b/lisp/emacs-lisp/cl-macs.el
index 2431e658368..7b69404cfac 100644
--- a/lisp/emacs-lisp/cl-macs.el
+++ b/lisp/emacs-lisp/cl-macs.el
@@ -3739,7 +3739,7 @@ macro that returns its `&whole' argument."
 (mapc (lambda (x) (function-put x 'important-return-value t))
        '(
          ;; Functions that are side-effect-free except for the
-         ;; behaviour of functions passed as argument.
+         ;; behavior of functions passed as argument.
          cl-mapcar cl-mapcan cl-maplist cl-map cl-mapcon
          cl-reduce
          cl-assoc cl-assoc-if cl-assoc-if-not
diff --git a/lisp/emacs-lisp/comp-common.el b/lisp/emacs-lisp/comp-common.el
index 6d94d1bd82e..b7a685223ed 100644
--- a/lisp/emacs-lisp/comp-common.el
+++ b/lisp/emacs-lisp/comp-common.el
@@ -49,11 +49,10 @@ This is intended for debugging the compiler itself.
   :version "28.1")
 
 (defcustom native-comp-never-optimize-functions
-  '(eval
-    ;; The following two are mandatory for Emacs to be working
-    ;; correctly (see comment in `advice--add-function'). DO NOT
-    ;; REMOVE.
-    macroexpand rename-buffer)
+  ;; We used to list those functions here that were advised during
+  ;; preload, but we now prefer to disallow preload advices in
+  ;; loadup.el (bug#67005).
+  '(eval)
   "Primitive functions to exclude from trampoline optimization.
 
 Primitive functions included in this list will not be called
diff --git a/lisp/emacs-lisp/comp-cstr.el b/lisp/emacs-lisp/comp-cstr.el
index e47e93cda18..339a6142178 100644
--- a/lisp/emacs-lisp/comp-cstr.el
+++ b/lisp/emacs-lisp/comp-cstr.el
@@ -797,7 +797,7 @@ DST is returned."
             (cl-loop
              for val in (valset src)
              ;; If (member value) is subtypep of all other sources then
-             ;; is good to be colleted.
+             ;; is good to be collected.
              when (cl-every (lambda (s)
                               (or (memql val (valset s))
                                   (cl-some (lambda (type)
diff --git a/lisp/emacs-lisp/comp-run.el b/lisp/emacs-lisp/comp-run.el
index 5335003e25b..4b1d2451a4e 100644
--- a/lisp/emacs-lisp/comp-run.el
+++ b/lisp/emacs-lisp/comp-run.el
@@ -33,6 +33,7 @@
 
 (eval-when-compile (require 'cl-lib))
 (require 'comp-common)
+(require 'bytecomp) ;; For `emacs-lisp-compilation-mode'.
 
 (defgroup comp-run nil
   "Emacs Lisp native compiler runtime."
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 73764eb1d79..3b2fd25e61c 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -224,13 +224,13 @@ Useful to hook into pass checkers.")
    finally return h)
   "Hash table function -> `comp-constraint'.")
 
-(defun comp-known-predicate-p (predicate)
+(defun comp--known-predicate-p (predicate)
   "Return t if PREDICATE is known."
   (when (or (gethash predicate comp-known-predicates-h)
             (gethash predicate (comp-cstr-ctxt-pred-type-h comp-ctxt)))
     t))
 
-(defun comp-pred-to-cstr (predicate)
+(defun comp--pred-to-cstr (predicate)
   "Given PREDICATE, return the corresponding constraint."
   (or (gethash predicate comp-known-predicates-h)
       (gethash predicate (comp-cstr-ctxt-pred-type-h comp-ctxt))))
@@ -430,7 +430,7 @@ non local exit (ends with an `unreachable' insn)."))
                                (:include comp-block))
   "A basic block holding only constraints.")
 
-(cl-defstruct (comp-edge (:copier nil) (:constructor make--comp-edge))
+(cl-defstruct (comp-edge (:copier nil) (:constructor comp--edge-make0))
   "An edge connecting two basic blocks."
   (src nil :type (or null comp-block))
   (dst nil :type (or null comp-block))
@@ -438,19 +438,19 @@ non local exit (ends with an `unreachable' insn)."))
           :documentation "The index number corresponding to this edge in the
  edge hash."))
 
-(defun make-comp-edge (&rest args)
+(defun comp--edge-make (&rest args)
   "Create a `comp-edge' with basic blocks SRC and DST."
   (let ((n (funcall (comp-func-edge-cnt-gen comp-func))))
     (puthash
      n
-     (apply #'make--comp-edge :number n args)
+     (apply #'comp--edge-make0 :number n args)
      (comp-func-edges-h comp-func))))
 
-(defun comp-block-preds (basic-block)
+(defun comp--block-preds (basic-block)
   "Return the list of predecessors of BASIC-BLOCK."
   (mapcar #'comp-edge-src (comp-block-in-edges basic-block)))
 
-(defun comp-gen-counter ()
+(defun comp--gen-counter ()
   "Return a sequential number generator."
   (let ((n -1))
     (lambda ()
@@ -484,9 +484,9 @@ CFG is mutated by a pass.")
              :documentation "LAP label -> LIMPLE basic block name.")
   (edges-h (make-hash-table) :type hash-table
          :documentation "Hash edge-num -> edge connecting basic two blocks.")
-  (block-cnt-gen (funcall #'comp-gen-counter) :type function
+  (block-cnt-gen (funcall #'comp--gen-counter) :type function
                  :documentation "Generates block numbers.")
-  (edge-cnt-gen (funcall #'comp-gen-counter) :type function
+  (edge-cnt-gen (funcall #'comp--gen-counter) :type function
                 :documentation "Generates edges numbers.")
   (has-non-local nil :type boolean
                  :documentation "t if non local jumps are present.")
@@ -525,39 +525,39 @@ In use by the back-end."
 
 
 
-(defun comp-equality-fun-p (function)
+(defun comp--equality-fun-p (function)
   "Equality functions predicate for FUNCTION."
   (when (memq function '(eq eql equal)) t))
 
-(defun comp-arithm-cmp-fun-p (function)
+(defun comp--arithm-cmp-fun-p (function)
   "Predicate for arithmetic comparison functions."
   (when (memq function '(= > < >= <=)) t))
 
-(defun comp-set-op-p (op)
+(defun comp--set-op-p (op)
   "Assignment predicate for OP."
   (when (memq op comp-limple-sets) t))
 
-(defun comp-assign-op-p (op)
+(defun comp--assign-op-p (op)
   "Assignment predicate for OP."
   (when (memq op comp-limple-assignments) t))
 
-(defun comp-call-op-p (op)
+(defun comp--call-op-p (op)
   "Call predicate for OP."
   (when (memq op comp-limple-calls) t))
 
-(defun comp-branch-op-p (op)
+(defun comp--branch-op-p (op)
   "Branch predicate for OP."
   (when (memq op comp-limple-branches) t))
 
-(defsubst comp-limple-insn-call-p (insn)
+(defsubst comp--limple-insn-call-p (insn)
   "Limple INSN call predicate."
-  (comp-call-op-p (car-safe insn)))
+  (comp--call-op-p (car-safe insn)))
 
-(defun comp-type-hint-p (func)
+(defun comp--type-hint-p (func)
   "Type-hint predicate for function name FUNC."
   (when (memq func comp-type-hints) t))
 
-(defun comp-func-unique-in-cu-p (func)
+(defun comp--func-unique-in-cu-p (func)
   "Return t if FUNC is known to be unique in the current compilation unit."
   (if (symbolp func)
       (cl-loop with h = (make-hash-table :test #'eq)
@@ -569,46 +569,46 @@ In use by the back-end."
                finally return t)
     t))
 
-(defsubst comp-symbol-func-to-fun (symbol-funcion)
+(defsubst comp--symbol-func-to-fun (symbol-funcion)
   "Given a function called SYMBOL-FUNCION return its `comp-func'."
   (gethash (gethash symbol-funcion (comp-ctxt-sym-to-c-name-h
                                     comp-ctxt))
            (comp-ctxt-funcs-h comp-ctxt)))
 
-(defun comp-function-pure-p (f)
+(defun comp--function-pure-p (f)
   "Return t if F is pure."
   (or (get f 'pure)
-      (when-let ((func (comp-symbol-func-to-fun f)))
+      (when-let ((func (comp--symbol-func-to-fun f)))
         (comp-func-pure func))))
 
-(defun comp-alloc-class-to-container (alloc-class)
+(defun comp--alloc-class-to-container (alloc-class)
   "Given ALLOC-CLASS, return the data container for the current context.
 Assume allocation class `d-default' as default."
   (cl-struct-slot-value 'comp-ctxt (or alloc-class 'd-default) comp-ctxt))
 
-(defsubst comp-add-const-to-relocs (obj)
+(defsubst comp--add-const-to-relocs (obj)
   "Keep track of OBJ into the ctxt relocations."
-  (puthash obj t (comp-data-container-idx (comp-alloc-class-to-container
+  (puthash obj t (comp-data-container-idx (comp--alloc-class-to-container
                                            comp-curr-allocation-class))))
 
 
 ;;; Log routines.
 
-(defun comp-prettyformat-mvar (mvar)
+(defun comp--prettyformat-mvar (mvar)
   (format "#(mvar %s %s %S)"
           (comp-mvar-id mvar)
           (comp-mvar-slot mvar)
           (comp-cstr-to-type-spec mvar)))
 
-(defun comp-prettyformat-insn (insn)
+(defun comp--prettyformat-insn (insn)
   (cond
    ((comp-mvar-p insn)
-    (comp-prettyformat-mvar insn))
+    (comp--prettyformat-mvar insn))
    ((proper-list-p insn)
-    (concat "(" (mapconcat #'comp-prettyformat-insn insn " ") ")"))
+    (concat "(" (mapconcat #'comp--prettyformat-insn insn " ") ")"))
    (t (prin1-to-string insn))))
 
-(defun comp-log-func (func verbosity)
+(defun comp--log-func (func verbosity)
   "Log function FUNC at VERBOSITY.
 VERBOSITY is a number between 0 and 3."
   (when (>= native-comp-verbose verbosity)
@@ -619,9 +619,9 @@ VERBOSITY is a number between 0 and 3."
      do (comp-log (concat "<" (symbol-name block-name) ">") verbosity)
         (cl-loop
          for insn in (comp-block-insns bb)
-         do (comp-log (comp-prettyformat-insn insn) verbosity)))))
+         do (comp-log (comp--prettyformat-insn insn) verbosity)))))
 
-(defun comp-log-edges (func)
+(defun comp--log-edges (func)
   "Log edges in FUNC."
   (let ((edges (comp-func-edges-h func)))
     (comp-log (format "\nEdges in function: %s\n"
@@ -963,7 +963,7 @@ STACK-OFF is the index of the first slot frame involved."
   "`comp-mvar' initializer."
   (let ((mvar (make--comp-mvar :slot slot)))
     (when const-vld
-      (comp-add-const-to-relocs constant)
+      (comp--add-const-to-relocs constant)
       (setf (comp-cstr-imm mvar) constant))
     (when type
       (setf (comp-mvar-typeset mvar) (list type)))
@@ -1008,7 +1008,7 @@ If DST-N is specified, use it; otherwise assume it to be 
the current slot."
 
 (defsubst comp-emit-setimm (val)
   "Set constant VAL to current slot."
-  (comp-add-const-to-relocs val)
+  (comp--add-const-to-relocs val)
   ;; Leave relocation index nil on purpose, will be fixed-up in final
   ;; by `comp-finalize-relocs'.
   (comp-emit `(setimm ,(comp-slot) ,val)))
@@ -1496,7 +1496,7 @@ and the annotation emission."
   (cl-loop for bb being the hash-value in (comp-func-blocks func)
            do (setf (comp-block-insns bb)
                     (nreverse (comp-block-insns bb))))
-  (comp-log-func func 2)
+  (comp--log-func func 2)
   func)
 
 (cl-defgeneric comp-prepare-args-for-top-level (function)
@@ -1570,7 +1570,7 @@ and the annotation emission."
 These are stored in the reloc data array."
   (let ((args (comp-prepare-args-for-top-level func)))
     (let ((comp-curr-allocation-class 'd-impure))
-      (comp-add-const-to-relocs (comp-func-byte-func func)))
+      (comp--add-const-to-relocs (comp-func-byte-func func)))
     (comp-emit
      (comp-call 'comp--register-lambda
                 ;; mvar to be fixed-up when containers are
@@ -1773,7 +1773,7 @@ into the C code forwarding the compilation unit."
    do (cl-loop
        for insn in (comp-block-insns b)
        for (op . args) = insn
-       if (comp-assign-op-p op)
+       if (comp--assign-op-p op)
          do (comp-collect-mvars (cdr args))
        else
          do (comp-collect-mvars args))))
@@ -1822,7 +1822,7 @@ The assume is emitted at the beginning of the block BB."
                                        (comp-cstr-negation-make rhs)
                                      rhs)))
               (comp-block-insns bb))))
-      ((pred comp-arithm-cmp-fun-p)
+      ((pred comp--arithm-cmp-fun-p)
        (when-let ((kind (if negated
                             (comp-negate-arithm-cmp-fun kind)
                           kind)))
@@ -1855,7 +1855,7 @@ Return OP otherwise."
   (cl-loop
    with new-bb = (make-comp-block-cstr :name bb-symbol
                                        :insns `((jump ,(comp-block-name 
bb-b))))
-   with new-edge = (make-comp-edge :src bb-a :dst new-bb)
+   with new-edge = (comp--edge-make :src bb-a :dst new-bb)
    for ed in (comp-block-in-edges bb-b)
    when (eq (comp-edge-src ed) bb-a)
    do
@@ -1886,7 +1886,7 @@ Keep on searching till EXIT-INSN is encountered."
      when (eq insn exit-insn)
      do (cl-return (and (comp-mvar-p res) res))
      do (pcase insn
-          (`(,(pred comp-assign-op-p) ,(pred targetp) ,rhs)
+          (`(,(pred comp--assign-op-p) ,(pred targetp) ,rhs)
            (setf res rhs)))
      finally (cl-assert nil))))
 
@@ -1967,14 +1967,18 @@ TARGET-BB-SYM is the symbol name of the target block."
          (set ,(and (pred comp-mvar-p) mvar-3)
               (call memq ,(and (pred comp-mvar-p) mvar-1) ,(and (pred 
comp-mvar-p) mvar-2)))
          (cond-jump ,(and (pred comp-mvar-p) mvar-3) ,(pred comp-mvar-p) ,bb1 
,bb2))
-       (push  `(assume ,mvar-tested ,(make-comp-mvar :type (comp-cstr-cl-tag 
mvar-tag)))
-              (comp-block-insns (comp-add-cond-cstrs-target-block b bb2)))
-       (push  `(assume ,mvar-tested ,(make-comp-mvar :type (comp-cstr-cl-tag 
mvar-tag) :neg t))
-              (comp-block-insns (comp-add-cond-cstrs-target-block b bb1))))
+       (comp-emit-assume 'and mvar-tested
+                         (make-comp-mvar :type (comp-cstr-cl-tag mvar-tag))
+                         (comp-add-cond-cstrs-target-block b bb2)
+                         nil)
+       (comp-emit-assume 'and mvar-tested
+                         (make-comp-mvar :type (comp-cstr-cl-tag mvar-tag))
+                         (comp-add-cond-cstrs-target-block b bb1)
+                         t))
       (`((set ,(and (pred comp-mvar-p) cmp-res)
-              (,(pred comp-call-op-p)
-               ,(and (or (pred comp-equality-fun-p)
-                         (pred comp-arithm-cmp-fun-p))
+              (,(pred comp--call-op-p)
+               ,(and (or (pred comp--equality-fun-p)
+                         (pred comp--arithm-cmp-fun-p))
                      fun)
                ,op1 ,op2))
         ;; (comment ,_comment-str)
@@ -2006,14 +2010,14 @@ TARGET-BB-SYM is the symbol name of the target block."
                               block-target negated)))
         finally (cl-return-from in-the-basic-block)))
       (`((set ,(and (pred comp-mvar-p) cmp-res)
-              (,(pred comp-call-op-p)
-               ,(and (pred comp-known-predicate-p) fun)
+              (,(pred comp--call-op-p)
+               ,(and (pred comp--known-predicate-p) fun)
                ,op))
         ;; (comment ,_comment-str)
         (cond-jump ,cmp-res ,(pred comp-mvar-p) . ,blocks))
        (cl-loop
         with target-mvar = (comp-cond-cstrs-target-mvar op (car insns-seq) b)
-        with cstr = (comp-pred-to-cstr fun)
+        with cstr = (comp--pred-to-cstr fun)
         for branch-target-cell on blocks
         for branch-target = (car branch-target-cell)
         for negated in '(t nil)
@@ -2025,14 +2029,14 @@ TARGET-BB-SYM is the symbol name of the target block."
         finally (cl-return-from in-the-basic-block)))
       ;; Match predicate on the negated branch (unless).
       (`((set ,(and (pred comp-mvar-p) cmp-res)
-              (,(pred comp-call-op-p)
-               ,(and (pred comp-known-predicate-p) fun)
+              (,(pred comp--call-op-p)
+               ,(and (pred comp--known-predicate-p) fun)
                ,op))
          (set ,neg-cmp-res (call eq ,cmp-res ,(pred comp-cstr-null-p)))
         (cond-jump ,neg-cmp-res ,(pred comp-mvar-p) . ,blocks))
        (cl-loop
         with target-mvar = (comp-cond-cstrs-target-mvar op (car insns-seq) b)
-        with cstr = (comp-pred-to-cstr fun)
+        with cstr = (comp--pred-to-cstr fun)
         for branch-target-cell on blocks
         for branch-target = (car branch-target-cell)
         for negated in '(nil t)
@@ -2084,10 +2088,10 @@ TARGET-BB-SYM is the symbol name of the target block."
    (comp-loop-insn-in-block bb
      (when-let ((match
                  (pcase insn
-                   (`(set ,lhs (,(pred comp-call-op-p) ,f . ,args))
+                   (`(set ,lhs (,(pred comp--call-op-p) ,f . ,args))
                     (when-let ((cstr-f (gethash f comp-known-func-cstr-h)))
                       (cl-values f cstr-f lhs args)))
-                   (`(,(pred comp-call-op-p) ,f . ,args)
+                   (`(,(pred comp--call-op-p) ,f . ,args)
                     (when-let ((cstr-f (gethash f comp-known-func-cstr-h)))
                       (cl-values f cstr-f nil args))))))
        (cl-multiple-value-bind (f cstr-f lhs args) match
@@ -2126,7 +2130,7 @@ blocks."
                 (comp-add-cond-cstrs-simple)
                  (comp-add-cond-cstrs)
                  (comp-add-call-cstr)
-                 (comp-log-func comp-func 3))))
+                 (comp--log-func comp-func 3))))
            (comp-ctxt-funcs-h comp-ctxt)))
 
 
@@ -2145,9 +2149,9 @@ blocks."
    do (cl-loop
        for insn in (comp-block-insns b)
        do (pcase insn
-            (`(set ,_lval (,(pred comp-call-op-p) ,f . ,_rest))
+            (`(set ,_lval (,(pred comp--call-op-p) ,f . ,_rest))
              (puthash f t h))
-            (`(,(pred comp-call-op-p) ,f . ,_rest)
+            (`(,(pred comp--call-op-p) ,f . ,_rest)
              (puthash f t h))))
    finally return (cl-loop
                    for f being each hash-key of h
@@ -2160,7 +2164,7 @@ blocks."
 (defun comp-pure-infer-func (f)
   "If all functions called by F are pure then F is pure too."
   (when (and (cl-every (lambda (x)
-                         (or (comp-function-pure-p x)
+                         (or (comp--function-pure-p x)
                              (eq x (comp-func-name f))))
                        (comp-collect-calls f))
              (not (eq (comp-func-pure f) t)))
@@ -2224,16 +2228,16 @@ blocks."
            for (op first second third forth) = last-insn
            do (cl-case op
                 (jump
-                 (make-comp-edge :src bb :dst (gethash first blocks)))
+                 (comp--edge-make :src bb :dst (gethash first blocks)))
                 (cond-jump
-                 (make-comp-edge :src bb :dst (gethash third blocks))
-                 (make-comp-edge :src bb :dst (gethash forth blocks)))
+                 (comp--edge-make :src bb :dst (gethash third blocks))
+                 (comp--edge-make :src bb :dst (gethash forth blocks)))
                 (cond-jump-narg-leq
-                 (make-comp-edge :src bb :dst (gethash second blocks))
-                 (make-comp-edge :src bb :dst (gethash third blocks)))
+                 (comp--edge-make :src bb :dst (gethash second blocks))
+                 (comp--edge-make :src bb :dst (gethash third blocks)))
                 (push-handler
-                 (make-comp-edge :src bb :dst (gethash third blocks))
-                 (make-comp-edge :src bb :dst (gethash forth blocks)))
+                 (comp--edge-make :src bb :dst (gethash third blocks))
+                 (comp--edge-make :src bb :dst (gethash forth blocks)))
                 (return)
                 (unreachable)
                 (otherwise
@@ -2250,7 +2254,7 @@ blocks."
                   (comp-block-out-edges (comp-edge-src edge)))
             (push edge
                   (comp-block-in-edges (comp-edge-dst edge))))
-           (comp-log-edges comp-func)))
+           (comp--log-edges comp-func)))
 
 (defun comp-collect-rev-post-order (basic-block)
   "Walk BASIC-BLOCK children and return their name in reversed post-order."
@@ -2306,7 +2310,7 @@ blocks."
        do (cl-loop
            for name in (cdr rev-bb-list)
            for b = (gethash name blocks)
-           for preds = (comp-block-preds b)
+           for preds = (comp--block-preds b)
            for new-idom = (first-processed preds)
            initially (setf changed nil)
            do (cl-loop for p in (delq new-idom preds)
@@ -2326,7 +2330,7 @@ blocks."
   (cl-loop with blocks = (comp-func-blocks comp-func)
            for b-name being each hash-keys of blocks
            using (hash-value b)
-           for preds = (comp-block-preds b)
+           for preds = (comp--block-preds b)
            when (length> preds 1) ; All joins
            do (cl-loop for p in preds
                        for runner = p
@@ -2358,7 +2362,7 @@ blocks."
              ;; Return t if a SLOT-N was assigned within BB.
              (cl-loop for insn in (comp-block-insns bb)
                       for op = (car insn)
-                      when (or (and (comp-assign-op-p op)
+                      when (or (and (comp--assign-op-p op)
                                     (eql slot-n (comp-mvar-slot (cadr insn))))
                                ;; fetch-handler is after a non local
                                ;; therefore clobbers all frame!!!
@@ -2424,7 +2428,7 @@ PRE-LAMBDA and POST-LAMBDA are called in pre or 
post-order if non-nil."
                  (setf (comp-vec-aref frame slot-n) mvar
                        (cadr insn) mvar))))
      (pcase insn
-       (`(,(pred comp-assign-op-p) ,(pred targetp) . ,_)
+       (`(,(pred comp--assign-op-p) ,(pred targetp) . ,_)
         (let ((mvar (comp-vec-aref frame slot-n)))
           (setf (cddr insn) (cl-nsubst-if mvar #'targetp (cddr insn))))
         (new-lvalue))
@@ -2511,7 +2515,7 @@ Return t when one or more block was removed, nil 
otherwise."
                  (comp-place-phis)
                  (comp-ssa-rename)
                  (comp-finalize-phis)
-                 (comp-log-func comp-func 3)
+                 (comp--log-func comp-func 3)
                  (setf (comp-func-ssa-status f) t))))
            (comp-ctxt-funcs-h comp-ctxt)))
 
@@ -2574,7 +2578,7 @@ Forward propagate immediate involed in assignments." ; 
FIXME: Typo.  Involved or
 
 (defun comp-function-foldable-p (f args)
   "Given function F called with ARGS, return non-nil when optimizable."
-  (and (comp-function-pure-p f)
+  (and (comp--function-pure-p f)
        (cl-every #'comp-cstr-imm-vld-p args)))
 
 (defun comp-function-call-maybe-fold (insn f args)
@@ -2582,7 +2586,7 @@ Forward propagate immediate involed in assignments." ; 
FIXME: Typo.  Involved or
 Return non-nil if the function is folded successfully."
   (cl-flet ((rewrite-insn-as-setimm (insn value)
                ;; See `comp-emit-setimm'.
-               (comp-add-const-to-relocs value)
+               (comp--add-const-to-relocs value)
                (setf (car insn) 'setimm
                      (cddr insn) `(,value))))
     (cond
@@ -2599,7 +2603,7 @@ Return non-nil if the function is folded successfully."
         ;; should do basic block pruning in order to be sure that this
         ;; is not dead-code.  This is now left to gcc, to be
         ;; implemented only if we want a reliable diagnostic here.
-        (let* ((f (if-let (f-in-ctxt (comp-symbol-func-to-fun f))
+        (let* ((f (if-let (f-in-ctxt (comp--symbol-func-to-fun f))
                       ;; If the function is IN the compilation ctxt
                       ;; and know to be pure.
                       (comp-func-byte-func f-in-ctxt)
@@ -2645,6 +2649,8 @@ Fold the call in case."
        (_
         (comp-cstr-shallow-copy lval rval))))
     (`(assume ,lval ,(and (pred comp-mvar-p) rval))
+     ;; NOTE we should probably assert this case in the future when
+     ;; will be possible.
      (comp-cstr-shallow-copy lval rval))
     (`(assume ,lval (,kind . ,operands))
      (cl-case kind
@@ -2676,7 +2682,7 @@ Fold the call in case."
                                                (comp-func-blocks comp-func))))
                              (or (comp-latch-p bb)
                                  (when (comp-block-cstr-p bb)
-                                   (comp-latch-p (car (comp-block-preds 
bb)))))))
+                                   (comp-latch-p (car (comp--block-preds 
bb)))))))
                          rest))
             (prop-fn (if from-latch
                          #'comp-cstr-union-no-range
@@ -2743,7 +2749,7 @@ Return t if something was changed."
                      (format "fwprop pass jammed into %s?" (comp-func-name 
f))))
                   (comp-log (format "Propagation run %d times\n" i) 2))
                  (comp-rewrite-non-locals)
-                 (comp-log-func comp-func 3))))
+                 (comp--log-func comp-func 3))))
            (comp-ctxt-funcs-h comp-ctxt)))
 
 
@@ -2766,7 +2772,7 @@ Return t if something was changed."
   "Given FUNC return the `comp-fun' definition in the current context.
 FUNCTION can be a function-name or byte compiled function."
   (if (symbolp func)
-      (comp-symbol-func-to-fun func)
+      (comp--symbol-func-to-fun func)
     (cl-assert (byte-code-function-p func))
     (gethash func (comp-ctxt-byte-func-to-func-h comp-ctxt))))
 
@@ -2783,6 +2789,14 @@ FUNCTION can be a function-name or byte compiled 
function."
                     (symbol-function callee)
                   (cl-assert (byte-code-function-p callee))
                   callee))
+             ;; Below call to `subrp' returns nil on an advised
+             ;; primitive F, so that we do not optimize calls to F
+             ;; with the funcall trampoline removal below.  But if F
+             ;; is advised while we compile its call, it is very
+             ;; likely to be advised also when that call is executed.
+             ;; And in that case an "unoptimized" call to F is
+             ;; actually cheaper since it avoids the call to the
+             ;; intermediate native trampoline (bug#67005).
              (subrp (subrp f))
              (comp-func-callee (comp-func-in-unit callee)))
         (cond
@@ -2804,7 +2818,7 @@ FUNCTION can be a function-name or byte compiled 
function."
          ((and comp-func-callee
                (comp-func-c-name comp-func-callee)
                (or (and (>= (comp-func-speed comp-func) 3)
-                        (comp-func-unique-in-cu-p callee))
+                        (comp--func-unique-in-cu-p callee))
                    (and (>= (comp-func-speed comp-func) 2)
                         ;; Anonymous lambdas can't be redefined so are
                         ;; always safe to optimize.
@@ -2816,7 +2830,7 @@ FUNCTION can be a function-name or byte compiled 
function."
                            args
                          (fill-args args (comp-args-max func-args)))))
             `(,call-type ,(comp-func-c-name comp-func-callee) ,@args)))
-         ((comp-type-hint-p callee)
+         ((comp--type-hint-p callee)
           `(call ,callee ,@args)))))))
 
 (defun comp-call-optim-func ()
@@ -2873,7 +2887,7 @@ Return the list of m-var ids nuked."
      do (cl-loop
          for insn in (comp-block-insns b)
          for (op arg0 . rest) = insn
-         if (comp-assign-op-p op)
+         if (comp--assign-op-p op)
            do (push (comp-mvar-id arg0) l-vals)
               (setf r-vals (nconc (comp-collect-mvar-ids rest) r-vals))
          else
@@ -2891,10 +2905,10 @@ Return the list of m-var ids nuked."
        for b being each hash-value of (comp-func-blocks comp-func)
        do (comp-loop-insn-in-block b
             (cl-destructuring-bind (op &optional arg0 arg1 &rest rest) insn
-              (when (and (comp-assign-op-p op)
+              (when (and (comp--assign-op-p op)
                          (memq (comp-mvar-id arg0) nuke-list))
                 (setf insn
-                      (if (comp-limple-insn-call-p arg1)
+                      (if (comp--limple-insn-call-p arg1)
                           arg1
                         `(comment ,(format "optimized out: %s"
                                            insn))))))))
@@ -2911,7 +2925,7 @@ Return the list of m-var ids nuked."
                 for i from 1
                 while (comp-dead-assignments-func)
                 finally (comp-log (format "dead code rm run %d times\n" i) 2)
-                (comp-log-func comp-func 3))))
+                (comp--log-func comp-func 3))))
            (comp-ctxt-funcs-h comp-ctxt)))
 
 
@@ -2951,7 +2965,7 @@ Return the list of m-var ids nuked."
                         (not (comp-func-has-non-local f)))
                (let ((comp-func f))
                  (comp-tco-func)
-                 (comp-log-func comp-func 3))))
+                 (comp--log-func comp-func 3))))
            (comp-ctxt-funcs-h comp-ctxt)))
 
 
@@ -2967,7 +2981,7 @@ These are substituted with a normal `set' op."
    for b being each hash-value of (comp-func-blocks comp-func)
    do (comp-loop-insn-in-block b
         (pcase insn
-          (`(set ,l-val (call ,(pred comp-type-hint-p) ,r-val))
+          (`(set ,l-val (call ,(pred comp--type-hint-p) ,r-val))
            (setf insn `(set ,l-val ,r-val)))))))
 
 (defun comp-remove-type-hints (_)
@@ -2976,7 +2990,7 @@ These are substituted with a normal `set' op."
              (when (>= (comp-func-speed f) 2)
                (let ((comp-func f))
                  (comp-remove-type-hints-func)
-                 (comp-log-func comp-func 3))))
+                 (comp--log-func comp-func 3))))
            (comp-ctxt-funcs-h comp-ctxt)))
 
 
@@ -3029,7 +3043,7 @@ Set it into the `type' slot."
                              finally return res)))
            (type `(function ,(comp-args-to-lambda-list (comp-func-l-args func))
                             ,(comp-cstr-to-type-spec res-mvar))))
-      (comp-add-const-to-relocs type)
+      (comp--add-const-to-relocs type)
       ;; Fix it up.
       (setf (comp-cstr-imm (comp-func-type func)) type))))
 
@@ -3058,7 +3072,7 @@ Update all insn accordingly."
   ;; Symbols imported by C inlined functions.  We do this here because
   ;; is better to add all objs to the relocation containers before we
   ;; compacting them.
-  (mapc #'comp-add-const-to-relocs '(nil t consp listp symbol-with-pos-p))
+  (mapc #'comp--add-const-to-relocs '(nil t consp listp symbol-with-pos-p))
 
   (let* ((d-default (comp-ctxt-d-default comp-ctxt))
          (d-default-idx (comp-data-container-idx d-default))
@@ -3113,7 +3127,7 @@ Prepare every function for final compilation and drive 
the C back-end."
   (let ((dir (file-name-directory name)))
     (comp-finalize-relocs)
     (maphash (lambda (_ f)
-               (comp-log-func f 1))
+               (comp--log-func f 1))
              (comp-ctxt-funcs-h comp-ctxt))
     (unless (file-exists-p dir)
       ;; In case it's created in the meanwhile.
@@ -3363,7 +3377,7 @@ the deferred compilation mechanism."
                    for pass in comp-passes
                    unless (memq pass comp-disabled-passes)
                    do
-                   (comp-log (format "(%s) Running pass %s:\n"
+                   (comp-log (format "\n(%s) Running pass %s:\n"
                                      function-or-file pass)
                              2)
                    (setf data (funcall pass data))
@@ -3483,7 +3497,7 @@ last directory in `native-comp-eln-load-path')."
 Make sure that eln file is younger than byte-compiled one and
 return the filename of this last.
 
-This function can be used only in conjuntion with
+This function can be used only in conjunction with
 `byte+native-compile' `byte-to-native-output-buffer-file' (see
 `batch-byte+native-compile')."
   (pcase byte-to-native-output-buffer-file
diff --git a/lisp/emacs-lisp/debug.el b/lisp/emacs-lisp/debug.el
index 5411088189d..e0b6ca31b9e 100644
--- a/lisp/emacs-lisp/debug.el
+++ b/lisp/emacs-lisp/debug.el
@@ -237,12 +237,11 @@ the debugger will not be entered."
          (unwind-protect
              (save-excursion
                (when (eq (car debugger-args) 'debug)
-                 ;; Skip the frames for backtrace-debug, byte-code,
-                 ;; debug--implement-debug-on-entry and the advice's `apply'.
-                 (backtrace-debug 4 t)
-                 ;; Place an extra debug-on-exit for macro's.
-                 (when (eq 'lambda (car-safe (cadr (backtrace-frame 4))))
-                   (backtrace-debug 5 t)))
+                 (let ((base (debugger--backtrace-base)))
+                   (backtrace-debug 1 t base) ;FIXME!
+                   ;; Place an extra debug-on-exit for macro's.
+                   (when (eq 'lambda (car-safe (cadr (backtrace-frame 1 
base))))
+                     (backtrace-debug 2 t base))))
                 (with-current-buffer debugger-buffer
                   (unless (derived-mode-p 'debugger-mode)
                    (debugger-mode))
@@ -343,11 +342,10 @@ Make functions into cross-reference buttons if DO-XREFS 
is non-nil."
 (defun debugger-setup-buffer (args)
   "Initialize the `*Backtrace*' buffer for entry to the debugger.
 That buffer should be current already and in `debugger-mode'."
-  (setq backtrace-frames (nthcdr
-                          ;; Remove debug--implement-debug-on-entry and the
-                          ;; advice's `apply' frame.
-                          (if (eq (car args) 'debug) 3 1)
-                          (backtrace-get-frames 'debug)))
+  (setq backtrace-frames
+        ;; The `base' frame is the one that gets index 0 and it is the entry to
+        ;; the debugger, so drop it with `cdr'.
+        (cdr (backtrace-get-frames (debugger--backtrace-base))))
   (when (eq (car-safe args) 'exit)
     (setq debugger-value (nth 1 args))
     (setf (cl-getf (backtrace-frame-flags (car backtrace-frames))
@@ -477,26 +475,29 @@ removes itself from that hook."
   (setq debugger-jumping-flag nil)
   (remove-hook 'post-command-hook 'debugger-reenable))
 
-(defun debugger-frame-number (&optional skip-base)
+(defun debugger-frame-number ()
   "Return number of frames in backtrace before the one point points at."
-  (let ((index (backtrace-get-index))
-        (count 0))
+  (let ((index (backtrace-get-index)))
     (unless index
       (error "This line is not a function call"))
-    (unless skip-base
-        (while (not (eq (cadr (backtrace-frame count)) 'debug))
-          (setq count (1+ count)))
-        ;; Skip debug--implement-debug-on-entry frame.
-        (when (eq 'debug--implement-debug-on-entry
-                  (cadr (backtrace-frame (1+ count))))
-          (setq count (+ 2 count))))
-    (+ count index)))
+    ;; We have 3 representations of the backtrace: the real in C in `specpdl',
+    ;; the one stored in `backtrace-frames' and the textual version in
+    ;; the buffer.  Check here that the one from `backtrace-frames' is in sync
+    ;; with the one from `specpdl'.
+    (cl-assert (equal (backtrace-frame-fun (nth index backtrace-frames))
+                      (nth 1 (backtrace-frame (1+ index)
+                                              (debugger--backtrace-base)))))
+    ;; The `base' frame is the one that gets index 0 and it is the entry to
+    ;; the debugger, so the first non-debugger frame is 1.
+    ;; This `+1' skips the same frame as the `cdr' in
+    ;; `debugger-setup-buffer'.
+    (1+ index)))
 
 (defun debugger-frame ()
   "Request entry to debugger when this frame exits.
 Applies to the frame whose line point is on in the backtrace."
   (interactive)
-  (backtrace-debug (debugger-frame-number) t)
+  (backtrace-debug (debugger-frame-number) t (debugger--backtrace-base))
   (setf
    (cl-getf (backtrace-frame-flags (nth (backtrace-get-index) 
backtrace-frames))
             :debug-on-exit)
@@ -507,7 +508,7 @@ Applies to the frame whose line point is on in the 
backtrace."
   "Do not enter debugger when this frame exits.
 Applies to the frame whose line point is on in the backtrace."
   (interactive)
-  (backtrace-debug (debugger-frame-number) nil)
+  (backtrace-debug (debugger-frame-number) nil (debugger--backtrace-base))
   (setf
    (cl-getf (backtrace-frame-flags (nth (backtrace-get-index) 
backtrace-frames))
             :debug-on-exit)
@@ -526,10 +527,8 @@ Applies to the frame whose line point is on in the 
backtrace."
 (defun debugger--backtrace-base ()
   "Return the function name that marks the top of the backtrace.
 See `backtrace-frame'."
-  (cond ((eq 'debug--implement-debug-on-entry
-            (cadr (backtrace-frame 1 'debug)))
-        'debug--implement-debug-on-entry)
-       (t 'debug)))
+  (or (cadr (memq :backtrace-base debugger-args))
+      #'debug))
 
 (defun debugger-eval-expression (exp &optional nframe)
   "Eval an expression, in an environment like that outside the debugger.
@@ -537,7 +536,7 @@ The environment used is the one when entering the 
activation frame at point."
   (interactive
    (list (read--expression "Eval in stack frame: ")))
   (let ((nframe (or nframe
-                    (condition-case nil (1+ (debugger-frame-number 'skip-base))
+                    (condition-case nil (debugger-frame-number)
                       (error 0)))) ;; If on first line.
        (base (debugger--backtrace-base)))
     (debugger-env-macro
@@ -670,7 +669,10 @@ functions to break on entry."
   (if (or inhibit-debug-on-entry debugger-jumping-flag)
       nil
     (let ((inhibit-debug-on-entry t))
-      (funcall debugger 'debug))))
+      (funcall debugger 'debug :backtrace-base
+               ;; An offset of 1 because we need to skip the advice
+               ;; OClosure that called us.
+               '(1 . debug--implement-debug-on-entry)))))
 
 ;;;###autoload
 (defun debug-on-entry (function)
diff --git a/lisp/emacs-lisp/eldoc.el b/lisp/emacs-lisp/eldoc.el
index 22144ed7c18..4ee825136c9 100644
--- a/lisp/emacs-lisp/eldoc.el
+++ b/lisp/emacs-lisp/eldoc.el
@@ -5,7 +5,7 @@
 ;; Author: Noah Friedman <friedman@splode.com>
 ;; Keywords: extensions
 ;; Created: 1995-10-06
-;; Version: 1.14.0
+;; Version: 1.15.0
 ;; Package-Requires: ((emacs "26.3"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -605,25 +605,29 @@ known to be truncated."
                     'maybe)))
        (get-buffer-window eldoc--doc-buffer t)))
 
-(defun eldoc-display-in-echo-area (docs _interactive)
+(defun eldoc-display-in-echo-area (docs interactive)
   "Display DOCS in echo area.
-Honor `eldoc-echo-area-use-multiline-p' and
+INTERACTIVE is non-nil if user explicitly invoked ElDoc.  Honor
+`eldoc-echo-area-use-multiline-p' and
 `eldoc-echo-area-prefer-doc-buffer'."
   (cond
-   (;; Check if we have permission to mess with echo area at all.  For
-    ;; example, if this-command is non-nil while running via an idle
-    ;; timer, we're still in the middle of executing a command, e.g. a
-    ;; query-replace where it would be annoying to overwrite the echo
-    ;; area.
-    (or
-     (not (eldoc-display-message-no-interference-p))
-     this-command
-     (not (eldoc--message-command-p last-command))))
-   (;; If we do but nothing to report, clear the echo area.
+   ((and (not interactive)
+         ;; When called non-interactively, check if we have permission
+         ;; to mess with echo area at all.  For example, if
+         ;; this-command is non-nil while running via an idle timer,
+         ;; we're still in the middle of executing a command, e.g. a
+         ;; query-replace where it would be annoying to overwrite the
+         ;; echo area.
+         (or
+          (not (eldoc-display-message-no-interference-p))
+          this-command
+          (not (eldoc--message-command-p last-command)))))
+   (;; If nothing to report, clear the echo area.
     (null docs)
     (eldoc--message nil))
    (t
-    ;; Otherwise, establish some parameters.
+    ;; Otherwise, proceed to change the echo area.  Start by
+    ;; establishing some parameters.
     (let*
         ((width (1- (window-width (minibuffer-window))))
          (val (if (and (symbolp eldoc-echo-area-use-multiline-p)
@@ -929,7 +933,7 @@ the docstrings eventually produced, using
       (let* ((eldoc--make-callback #'make-callback)
              (res (funcall eldoc-documentation-strategy)))
         ;; Observe the old and the new protocol:
-        (cond (;; Old protocol: got string, e-d-strategy is iself the
+        (cond (;; Old protocol: got string, e-d-strategy is itself the
                ;; origin function, and we output immediately;
                (stringp res)
                (register-doc 0 res nil eldoc-documentation-strategy)
diff --git a/lisp/emacs-lisp/ert-font-lock.el b/lisp/emacs-lisp/ert-font-lock.el
new file mode 100644
index 00000000000..8bde83bf278
--- /dev/null
+++ b/lisp/emacs-lisp/ert-font-lock.el
@@ -0,0 +1,364 @@
+;;; ert-font-lock.el --- ERT Font Lock   -*- lexical-binding: t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; Author: Vladimir Kazanov
+;; Keywords: lisp, tools
+
+;; 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/>.
+
+;;; Commentary:
+;;
+;; ERT Font Lock is an extension to the Emacs Lisp Regression Test
+;; library (ERT) providing a convenient way to check syntax
+;; highlighting provided by font-lock.
+;;
+;; ert-font-lock entry points are functions
+;; `ert-font-lock-test-string' and `ert-font-lock-test-file' and
+;; convenience macros: `ert-font-lock-deftest' and
+;; `ert-font-lock-deftest-file'.
+;;
+;; See unit tests in ert-font-lock-tests.el for usage examples.
+
+;;; Code:
+
+(require 'ert)
+(require 'newcomment)
+(require 'pcase)
+
+(defconst ert-font-lock--assertion-re
+  (rx
+   ;; column specifiers
+   (group (or "^" "<-"))
+   (one-or-more " ")
+   ;; optional negation of the face specification
+   (group (optional "!"))
+   ;; face symbol name
+   (group (one-or-more (or alphanumeric "-" "_" "."))))
+  "An ert-font-lock assertion regex.")
+
+(defun ert-font-lock--validate-major-mode (mode)
+  "Validate if MODE is a valid major mode."
+  (unless (functionp mode)
+    (error "Invalid major mode: %S. Please specify a valid major mode for
+ syntax highlighting tests" mode)))
+
+(defun ert-font-lock--test-body-str (mode str test-name)
+  "Run assertions from STR.
+Argument MODE - major mode to test.
+Argument TEST-NAME - name of the currently running ert test."
+  (ert-font-lock--validate-major-mode mode)
+  (with-temp-buffer
+    (insert str)
+    (funcall mode)
+    (font-lock-ensure)
+    (let ((tests (ert-font-lock--parse-comments)))
+      (ert-font-lock--check-faces tests)))
+  test-name)
+
+(defun ert-font-lock--test-body-file (mode file test-name)
+  "Run assertions from FILE.
+Argument MODE - major mode to test.
+Argument TEST-NAME - name of the currently running ert test."
+  (ert-font-lock--validate-major-mode mode)
+  (ert-font-lock-test-file file mode)
+  test-name)
+
+(defun ert-font-lock--parse-macro-args (doc-keys-mode-arg)
+  "Parse DOC-KEYS-MODE-ARG macro argument list."
+  (let (doc doc-p mode arg)
+
+    (when (stringp (car doc-keys-mode-arg))
+      (setq doc (pop doc-keys-mode-arg)
+            doc-p t))
+
+    (pcase-let
+        ((`(,keys ,mode-arg)
+          (ert--parse-keys-and-body doc-keys-mode-arg)))
+
+      (unless (symbolp (car mode-arg))
+        (error "A major mode symbol expected: %S" (car mode-arg)))
+      (setq mode (pop mode-arg))
+
+      (unless (stringp (car mode-arg))
+        (error "A string or file with assertions expected: %S" (car mode-arg)))
+      (setq arg (pop mode-arg))
+
+      (list doc doc-p keys mode arg))))
+
+;;;###autoload
+(defmacro ert-font-lock-deftest (name &rest docstring-keys-mode-and-str)
+  "Define test NAME (a symbol) using assertions from TEST-STR.
+
+Other than MAJOR-MODE and TEST-STR parameters, this macro accepts
+the same parameters and keywords as `ert-deftest' and is intended
+to be used through `ert'.
+
+\(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \
+[:tags \\='(TAG...)] MAJOR-MODE TEST-STR)"
+  (declare (debug (&define [&name "test@" symbolp]
+                           sexp [&optional stringp]
+                           [&rest keywordp sexp]
+                           symbolp
+                           stringp))
+           (doc-string 3)
+           (indent 2))
+  (pcase-let ((`(,documentation
+                 ,documentation-supplied-p
+                 ,keys ,mode ,arg)
+               (ert-font-lock--parse-macro-args docstring-keys-mode-and-str)))
+
+    `(ert-set-test ',name
+                   (make-ert-test
+                    :name ',name
+                    ,@(when documentation-supplied-p
+                        `(:documentation ,documentation))
+                    ,@(when (map-contains-key keys :expected-result)
+                        `(:expected-result-type ,(map-elt keys 
:expected-result)))
+                    ,@(when (map-contains-key keys :tags)
+                        `(:tags ,(map-elt keys :tags)))
+                    :body (lambda () (ert-font-lock--test-body-str ',mode ,arg 
',name))
+
+                    :file-name ,(or (macroexp-file-name) buffer-file-name)))))
+
+;;;###autoload
+(defmacro ert-font-lock-deftest-file (name &rest docstring-keys-mode-and-file)
+  "Define test NAME (a symbol) using assertions from FILE.
+
+FILE - path to a file with assertions in ERT resource director as
+return by `ert-resource-directory'.
+
+Other than MAJOR-MODE and FILE parameters, this macro accepts the
+same parameters and keywords as `ert-deftest' and is intended to
+be used through `ert'.
+
+\(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] \
+[:tags \\='(TAG...)] MAJOR-MODE FILE)"
+  (declare (debug (&define [&name "test@" symbolp]
+                           sexp [&optional stringp]
+                           [&rest keywordp sexp]
+                           symbolp
+                           stringp))
+           (doc-string 3)
+           (indent 2))
+
+  (pcase-let ((`(,documentation
+                 ,documentation-supplied-p
+                 ,keys ,mode ,arg)
+               (ert-font-lock--parse-macro-args docstring-keys-mode-and-file)))
+
+    `(ert-set-test ',name
+                   (make-ert-test
+                    :name ',name
+                    ,@(when documentation-supplied-p
+                        `(:documentation ,documentation))
+                    ,@(when (map-contains-key keys :expected-result)
+                        `(:expected-result-type ,(map-elt keys 
:expected-result)))
+                    ,@(when (map-contains-key keys :tags)
+                        `(:tags ,(map-elt keys :tags)))
+                    :body (lambda () (ert-font-lock--test-body-file
+                                 ',mode (ert-resource-file ,arg) ',name))
+                    :file-name ,(or (macroexp-file-name) buffer-file-name)))))
+
+(defun ert-font-lock--in-comment-p ()
+  "Check if the current point is inside a comment."
+  (nth 4 (syntax-ppss)))
+
+(defun ert-font-lock--comment-start-p ()
+  "Check if the current point starts a comment."
+  (or
+   ;; regexps use syntax tables so let's check that first
+   (looking-at "\\s<")
+
+   ;; check newcomment.el facilities
+   (and comment-start (looking-at (regexp-quote comment-start)))
+   (and comment-start-skip (looking-at comment-start-skip))
+
+   ;; sometimes comment syntax is just hardcoded
+   (and (derived-mode-p '(c-mode c++-mode java-mode))
+        (looking-at-p "//"))))
+
+(defun ert-font-lock--line-comment-p ()
+  "Return t if the current line is a comment-only line."
+  (syntax-ppss)
+  (save-excursion
+    (beginning-of-line)
+    (skip-syntax-forward " ")
+    ;; skip empty lines
+    (unless (eolp)
+      (or
+       ;; multiline comments
+       (ert-font-lock--in-comment-p)
+
+       ;; single line comments
+       (ert-font-lock--comment-start-p)))))
+
+(defun ert-font-lock--line-assertion-p ()
+  "Return t if the current line contains an assertion."
+  (syntax-ppss)
+  (save-excursion
+    (beginning-of-line)
+    (skip-syntax-forward " ")
+    (re-search-forward ert-font-lock--assertion-re
+                       (line-end-position) t 1)))
+
+(defun ert-font-lock--goto-first-char ()
+  "Move the point to the first character."
+  (beginning-of-line)
+  (skip-syntax-forward " "))
+
+(defun ert-font-lock--get-first-char-column ()
+  "Get the position of the first non-empty char in the current line."
+  (save-excursion
+    (ert-font-lock--goto-first-char)
+    (- (point) (line-beginning-position))))
+
+(defun ert-font-lock--parse-comments ()
+  "Read test assertions from comments in the current buffer."
+  (let ((tests '())
+        (curline 1)
+        (linetocheck -1))
+
+    (goto-char (point-min))
+
+    ;; Go through all lines, for comments check if there are
+    ;; assertions. For non-comment and comment/non-assert lines
+    ;; remember the last line seen.
+    (while (not (eobp))
+      (catch 'nextline
+
+        ;; Not a comment? remember the line, move to the next one
+        (unless (ert-font-lock--line-comment-p)
+          (setq linetocheck curline)
+          (throw 'nextline t))
+
+        ;; A comment. Not an assertion? remember the line to be
+        ;; checked, move to the next line
+        (unless (ert-font-lock--line-assertion-p)
+          (setq linetocheck curline)
+          (throw 'nextline t))
+
+
+        ;; Collect the assertion
+        (when (re-search-forward ert-font-lock--assertion-re
+                                 (line-end-position) t 1)
+
+          (unless (> linetocheck -1)
+            (user-error "Invalid test comment syntax at line %d. Expected a 
line to test before the comment line" curline))
+
+          ;; construct a test
+          (let* (;; either comment start char column (for arrows) or
+                 ;; caret column
+                 (column-checked (if (equal (match-string-no-properties 1) "^")
+                                     (- (match-beginning 1) 
(line-beginning-position))
+                                   (ert-font-lock--get-first-char-column)))
+                 ;; negate the face?
+                 (negation (string-equal (match-string-no-properties 2) "!"))
+                 ;; the face that is supposed to be in the position specified
+                 (face (match-string-no-properties 3)))
+
+            (push (list :line-checked linetocheck
+                        :line-assert curline
+                        :column-checked column-checked
+                        :face face
+                        :negation negation)
+                  tests))))
+
+      ;; next line
+      (setq curline (1+ curline))
+      (forward-line 1))
+
+    (reverse tests)))
+
+(defun ert-font-lock--point-at-line-and-column (line column)
+  "Get the buffer position for LINE and COLUMN."
+  (save-excursion
+    (goto-char (point-min))
+    (forward-line (1- line))
+    (move-to-column column)
+    (point)))
+
+(defun ert-font-lock--get-line (line-number)
+  "Return the content of the line specified by LINE-NUMBER."
+  (save-excursion
+    (goto-char (point-min))
+    (forward-line (1- line-number))
+    (buffer-substring-no-properties (line-beginning-position) 
(line-end-position))))
+
+(defun ert-font-lock--check-faces (tests)
+  "Check if the current buffer is fontified correctly.
+TESTS - tests to run.
+
+The function is meant to be run from within an ERT test."
+  (dolist (test tests)
+    (let* ((line-checked (plist-get test :line-checked))
+           (line-assert (plist-get test :line-assert))
+           (column-checked (plist-get test :column-checked))
+           (expected-face (intern (plist-get test :face)))
+           (negation (plist-get test :negation))
+
+           (actual-face (get-text-property 
(ert-font-lock--point-at-line-and-column line-checked column-checked) 'face))
+           (line-str (ert-font-lock--get-line line-checked))
+           (line-assert-str (ert-font-lock--get-line line-assert)))
+
+      (when (not (eq actual-face expected-face))
+        (ert-fail
+         (list (format "Expected face %S, got %S on line %d column %d"
+                       expected-face actual-face line-checked column-checked)
+               :line line-str
+               :assert line-assert-str)))
+
+      (when (and negation (eq actual-face expected-face))
+        (ert-fail
+         (list (format "Did not expect face %S face on line %d, column %d"
+                       actual-face line-checked column-checked)
+               :line line-str
+               :assert line-assert-str))))))
+
+;;;###autoload
+(defun ert-font-lock-test-string (test-string mode)
+  "Check font faces in TEST-STRING set by MODE.
+
+The function is meant to be run from within an ERT test."
+  (ert-font-lock--validate-major-mode mode)
+  (with-temp-buffer
+    (insert test-string)
+    (funcall mode)
+    (font-lock-ensure)
+
+    (ert-font-lock--check-faces (ert-font-lock--parse-comments)))
+
+  (ert-pass))
+
+;;;###autoload
+(defun ert-font-lock-test-file (filename mode)
+  "Check font faces in FILENAME set by MODE.
+
+The function is meant to be run from within an ERT test."
+  (ert-font-lock--validate-major-mode mode)
+  (with-temp-buffer
+    (insert-file-contents filename)
+    (funcall mode)
+    (font-lock-ensure)
+
+    (ert-font-lock--check-faces (ert-font-lock--parse-comments)))
+
+  (ert-pass))
+
+
+(provide 'ert-font-lock)
+
+;;; ert-font-lock.el ends here
diff --git a/lisp/emacs-lisp/ert.el b/lisp/emacs-lisp/ert.el
index d0582c4df4f..de9935da505 100644
--- a/lisp/emacs-lisp/ert.el
+++ b/lisp/emacs-lisp/ert.el
@@ -99,7 +99,7 @@ Even modest settings for `print-length' and `print-level' can
 produce extremely long lines in backtraces and lengthy delays in
 forming them.  This variable governs the target maximum line
 length by manipulating these two variables while printing stack
-traces.  Setting this variable to t will re-use the value of
+traces.  Setting this variable to t will reuse the value of
 `backtrace-line-length' while printing stack traces in ERT batch
 mode.  Any other value will be temporarily bound to
 `backtrace-line-length' when producing stack traces in batch
diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index 5d31253fe2d..9f40c1f3c93 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -638,7 +638,7 @@ REF must have been previously obtained with `gv-ref'."
 
 ;;; Generalized variables.
 
-;; You'd think noone would write `(setf (error ...) ..)' but it
+;; You'd think no one would write `(setf (error ...) ..)' but it
 ;; appears naturally as the result of macroexpansion of things like
 ;; (setf (pcase-exhaustive ...)).
 ;; We could generalize this to `throw' and `signal', but it seems
diff --git a/lisp/emacs-lisp/lisp.el b/lisp/emacs-lisp/lisp.el
index ee481dc4ed3..c2d9b12c8ad 100644
--- a/lisp/emacs-lisp/lisp.el
+++ b/lisp/emacs-lisp/lisp.el
@@ -93,7 +93,7 @@ report errors as appropriate for this kind of usage."
 
 (defun mark-sexp (&optional arg allow-extend)
   "Set mark ARG sexps from point or move mark one sexp.
-When called from Lisp with ALLOW-EXTEND ommitted or nil, mark is
+When called from Lisp with ALLOW-EXTEND omitted or nil, mark is
 set ARG sexps from point.
 With ARG and ALLOW-EXTEND both non-nil (interactively, with prefix
 argument), the place to which mark goes is the same place \\[forward-sexp]
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index 6eb670d6dc1..615a6622ce6 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -533,17 +533,18 @@ definitions to shadow the loaded ones for use in file 
byte-compilation."
 (defun macroexp-parse-body (body)
   "Parse a function BODY into (DECLARATIONS . EXPS)."
   (let ((decls ()))
-    ;; If there is only a string literal with nothing following, we
-    ;; consider this to be part of the body (the return value) rather
-    ;; than a declaration at this point.
-    (unless (and (null (cdr body)) (stringp (car body)))
-      (while
-          (and body
-               (let ((e (car body)))
-                 (or (stringp e)
-                     (memq (car-safe e)
-                           '(:documentation declare interactive cl-declare)))))
-        (push (pop body) decls)))
+    (while
+        (and body
+             (let ((e (car body)))
+               (or (and (stringp e)
+                        ;; If there is only a string literal with
+                        ;; nothing following, we consider this to be
+                        ;; part of the body (the return value) rather
+                        ;; than a declaration at this point.
+                        (cdr body))
+                   (memq (car-safe e)
+                         '(:documentation declare interactive cl-declare)))))
+      (push (pop body) decls))
     (cons (nreverse decls) body)))
 
 (defun macroexp-progn (exps)
diff --git a/lisp/emacs-lisp/nadvice.el b/lisp/emacs-lisp/nadvice.el
index 42027c01491..9f2b42f5765 100644
--- a/lisp/emacs-lisp/nadvice.el
+++ b/lisp/emacs-lisp/nadvice.el
@@ -509,8 +509,6 @@ HOW can be one of:
 <<>>"
   ;; TODO:
   ;; - record the advice location, to display in describe-function.
-  ;; - change all defadvice in lisp/**/*.el.
-  ;; - obsolete advice.el.
   (let* ((f (symbol-function symbol))
         (nf (advice--normalize symbol f)))
     (unless (eq f nf) (fset symbol nf))
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index 9780e4d53de..bef498f997c 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -29,7 +29,7 @@
 ;; To install a package from source use `package-vc-install'.  If you
 ;; aren't interested in activating a package, you can use
 ;; `package-vc-checkout' instead, which will prompt you for a target
-;; directory.  If you wish to re-use an existing checkout, the command
+;; directory.  If you wish to reuse an existing checkout, the command
 ;; `package-vc-install-from-checkout' will create a symbolic link and
 ;; prepare the package.
 ;;
@@ -503,10 +503,6 @@ identify a package as a VC package later on), building
 documentation and marking the package as installed."
   (let ((pkg-spec (package-vc--desc->spec pkg-desc))
         missing)
-    ;; Remove any previous instance of PKG-DESC from `package-alist'
-    (let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
-      (when pkgs
-        (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
 
     ;; In case the package was installed directly from source, the
     ;; dependency list wasn't know beforehand, and they might have
@@ -576,6 +572,11 @@ documentation and marking the package as installed."
         (dolist (doc-file (ensure-list (plist-get pkg-spec :doc)))
           (package-vc--build-documentation pkg-desc doc-file))))
 
+    ;; Remove any previous instance of PKG-DESC from `package-alist'
+    (let ((pkgs (assq (package-desc-name pkg-desc) package-alist)))
+      (when pkgs
+        (setf (cdr pkgs) (seq-remove #'package-vc-p (cdr pkgs)))))
+
     ;; Update package-alist.
     (let ((new-desc (package-load-descriptor pkg-dir)))
       ;; Activation has to be done before compilation, so that if we're
@@ -862,7 +863,7 @@ 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
+package name as a symbol, and SPEC is a plist that specifies how
 to fetch and build the package.  For possible values, see the
 subsection \"Specifying Package Sources\" in the Info
 node `(emacs)Fetching Package Sources'.
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index d4bb6710283..bed6e74c921 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -1720,18 +1720,26 @@ The variable `package-load-list' controls which 
packages to load."
                    package-quickstart-file))))
     ;; The quickstart file presumes that it has a blank slate,
     ;; so don't use it if we already activated some packages.
-    (if (and qs (not (bound-and-true-p package-activated-list)))
-        ;; Skip load-source-file-function which would slow us down by a factor
-        ;; 2 when loading the .el file (this assumes we were careful to
-        ;; save this file so it doesn't need any decoding).
-        (let ((load-source-file-function nil))
-          (unless (boundp 'package-activated-list)
-            (setq package-activated-list nil))
-          (load qs nil 'nomessage))
-      (require 'package)
-      (package--activate-all)))))
+    (or (and qs (not (bound-and-true-p package-activated-list))
+             ;; Skip `load-source-file-function' which would slow us down by
+             ;; a factor 2 when loading the .el file (this assumes we were
+             ;; careful to save this file so it doesn't need any decoding).
+             (with-demoted-errors "Error during quickstart: %S"
+               (let ((load-source-file-function nil))
+                 (unless (boundp 'package-activated-list)
+                   (setq package-activated-list nil))
+                 (load qs nil 'nomessage)
+                 t)))
+        (progn
+          (require 'package)
+          ;; Silence the "unknown function" warning when this is compiled
+          ;; inside `loaddefs.el'.
+          ;; FIXME: We use `with-no-warnings' because the effect of
+          ;; `declare-function' is currently not scoped, so if we use
+          ;; it here, we end up with a redefinition warning instead :-)
+          (with-no-warnings
+            (package--activate-all)))))))
 
-;;;###autoload
 (defun package--activate-all ()
   (dolist (elt (package--alist))
     (condition-case err
diff --git a/lisp/erc/erc-backend.el b/lisp/erc/erc-backend.el
index 7ff55de0d0c..0c336540483 100644
--- a/lisp/erc/erc-backend.el
+++ b/lisp/erc/erc-backend.el
@@ -101,39 +101,25 @@
 (eval-when-compile (require 'cl-lib))
 (require 'erc-common)
 
-(defvar erc--called-as-input-p)
 (defvar erc--display-context)
 (defvar erc--target)
-(defvar erc--cmem-from-nick-function)
 (defvar erc-channel-list)
-(defvar erc-channel-users)
+(defvar erc-channel-members)
 (defvar erc-default-nicks)
 (defvar erc-default-recipients)
 (defvar erc-ensure-target-buffer-on-privmsg)
-(defvar erc-format-nick-function)
-(defvar erc-format-query-as-channel-p)
 (defvar erc-hide-prompt)
 (defvar erc-input-marker)
 (defvar erc-insert-marker)
-(defvar erc-invitation)
 (defvar erc-join-buffer)
-(defvar erc-kill-buffer-on-part)
-(defvar erc-kill-server-buffer-on-quit)
-(defvar erc-log-p)
-(defvar erc-minibuffer-ignored)
 (defvar erc-networks--id)
 (defvar erc-nick)
 (defvar erc-nick-change-attempt-count)
-(defvar erc-prompt-for-channel-key)
-(defvar erc-prompt-hidden)
-(defvar erc-receive-query-display)
-(defvar erc-receive-query-display-defer)
-(defvar erc-reuse-buffers)
 (defvar erc-verbose-server-ping)
-(defvar erc-whowas-on-nosuchnick)
 
 (declare-function erc--init-channel-modes "erc" (channel raw-args))
 (declare-function erc--open-target "erc" (target))
+(declare-function erc--parse-nuh "erc" (string))
 (declare-function erc--target-from-string "erc" (string))
 (declare-function erc--update-modes "erc" (raw-args))
 (declare-function erc-active-buffer "erc" nil)
@@ -156,7 +142,6 @@
 (declare-function erc-display-server-message "erc" (_proc parsed))
 (declare-function erc-emacs-time-to-erc-time "erc" (&optional specified-time))
 (declare-function erc-format-message "erc" (msg &rest args))
-(declare-function erc-format-privmessage "erc" (nick msg privp msgp))
 (declare-function erc-get-buffer "erc" (target &optional proc))
 (declare-function erc-handle-login "erc" nil)
 (declare-function erc-handle-user-status-change "erc" (type nlh &optional l))
@@ -187,6 +172,9 @@
 (declare-function erc-update-mode-line-buffer "erc" (buffer))
 (declare-function erc-wash-quit-reason "erc" (reason nick login host))
 
+(declare-function erc--determine-speaker-message-format-args "erc"
+                  (nick target message queryp privmsgp statusmsgp inputp
+                        &optional prefix disp-nick))
 (declare-function erc-display-message "erc"
                   (parsed type buffer msg &rest args))
 (declare-function erc-get-buffer-create "erc"
@@ -816,6 +804,7 @@ Make sure you are in an ERC buffer when running this."
                   nil nil nil erc-session-client-certificate
                   erc-session-username
                   (erc-networks--id-given erc-networks--id))
+        (defvar erc-reuse-buffers)
         (unless (with-suppressed-warnings ((obsolete erc-reuse-buffers))
                   erc-reuse-buffers)
           (cl-assert (not (eq buffer (current-buffer)))))))))
@@ -1038,6 +1027,7 @@ Conditionally try to reconnect and take appropriate 
action."
           (erc-update-mode-line)
           ;; Kill server buffer if user wants it
           (set-buffer-modified-p nil)
+          (defvar erc-kill-server-buffer-on-quit)
           (when erc-kill-server-buffer-on-quit
             (kill-buffer (current-buffer))))
       ;; unexpected disconnect
@@ -1055,6 +1045,7 @@ Conditionally try to reconnect and take appropriate 
action."
   (when-let (((null erc--hidden-prompt-overlay))
              (ov (make-overlay erc-insert-marker (1- erc-input-marker)
                                nil 'front-advance)))
+    (defvar erc-prompt-hidden)
     (overlay-put ov 'display erc-prompt-hidden)
     (setq erc--hidden-prompt-overlay ov)))
 
@@ -1117,11 +1108,10 @@ Change value of property `erc-prompt' from t to 
`hidden'."
                    (setq erc-server-ping-handler nil)))
           (run-hook-with-args 'erc-disconnected-hook
                               (erc-current-nick) (system-name) "")
-          (dolist (buf (erc-buffer-filter (lambda () (boundp 
'erc-channel-users)) cproc))
-            (with-current-buffer buf
-              (when (erc--target-channel-p erc--target)
-                (setf (erc--target-channel-joined-p erc--target) nil))
-              (setq erc-channel-users (make-hash-table :test 'equal))))
+          (erc-with-all-buffers-of-server cproc (lambda () erc-channel-members)
+            (when (erc--target-channel-p erc--target)
+              (setf (erc--target-channel-joined-p erc--target) nil))
+            (clrhash erc-channel-members))
           ;; Hide the prompt
           (erc--hide-prompt cproc)
           ;; Decide what to do with the buffer
@@ -1716,6 +1706,7 @@ add things to `%s' instead."
         (chnl (erc-response.contents parsed)))
     (pcase-let ((`(,nick ,login ,host)
                  (erc-parse-user (erc-response.sender parsed))))
+      (defvar erc-invitation)
       (setq erc-invitation chnl)
       (when (string= target (erc-current-nick))
         (erc-display-message
@@ -1888,6 +1879,7 @@ add things to `%s' instead."
         (with-suppressed-warnings ((obsolete erc-delete-default-channel))
           (erc-delete-default-channel chnl buffer))
         (erc-update-mode-line buffer)
+        (defvar erc-kill-buffer-on-part)
         (when erc-kill-buffer-on-part
           (kill-buffer buffer))))))
 
@@ -1915,16 +1907,80 @@ add things to `%s' instead."
          ?s (if (/= erc-server-lag 1) "s" "")))
       (erc-update-mode-line))))
 
+(defun erc--statusmsg-target (target)
+  "Return actual target from given TARGET if it has a leading prefix char."
+  (and-let* ((erc-ensure-target-buffer-on-privmsg)
+             ((not (eq erc-ensure-target-buffer-on-privmsg 'status)))
+             ((not (erc-channel-p target)))
+             (chars (erc--get-isupport-entry 'STATUSMSG 'single))
+             ((string-search (string (aref target 0)) chars))
+             (trimmed (substring target 1))
+             ((erc-channel-p trimmed)))
+    trimmed))
+
+;; Moved to this file from erc.el in ERC 5.6.
+(defvar-local erc-current-message-catalog 'english
+  "Current language or context catalog for formatting inserted messages.
+See `erc-format-message'.")
+
+;; This variable can be made public if the current design proves
+;; sufficient.
+(defvar erc--message-speaker-catalog '-speaker
+  "The \"speaker\" catalog symbol used to format PRIVMSGs and NOTICEs.
+
+This symbol defines a \"catalog\" of variables and functions
+whose names reflect their membership via a corresponding CATALOG
+component, as in \"erc-message-CATALOG-KEY\".  Here, KEY refers
+to a common set of interface members (variables or functions),
+that an implementer must define:
+
+- `statusmsg' and `statusmsg-input': PRIVMSGs whose target is a
+   status-prefixed channel; the latter is the \"echoed\" version
+
+- `chan-privmsg', `query-privmsg', `chan-notice', `query-notice':
+   standard chat messages traditionally prefixed by a <nickname>
+   indicating the message's \"speaker\"
+
+- `input-chan-privmsg', `input-query-privmsg', `input-query-notice',
+  `input-chan-notice': \"echoed\" versions of the above
+
+- `ctcp-action', `ctcp-action-input', `ctcp-action-statusmsg',
+  `ctcp-action-statusmsg-input': \"CTCP ACTION\" versions of the
+   above
+
+The other part of this interface is the per-key collection of
+`format-spec' parameters members must support.  For simplicity,
+this catalog currently defines a common set for all keys, some of
+which may be assigned the empty string when not applicable:
+
+  %n - nickname
+  %m - message body
+  %p - nickname's status prefix (when applicable)
+  %s - current target's STATUSMSG prefix (when applicable)
+
+As an added means of communicating with various modules, if this
+catalog's symbol has the property `erc--msg-prop-overrides',
+consumers calling `erc-display-message' will see the value added
+to the `erc--msg-props' \"environment\" in modification hooks,
+like `erc-insert-modify-hook'.")
+
+(defvar erc--speaker-status-prefix-wanted-p (gensym "erc-")
+  "Sentinel to detect whether `erc-format-@nick' has just run.")
+
 (define-erc-response-handler (PRIVMSG NOTICE)
   "Handle private messages, including messages in channels." nil
   (let ((sender-spec (erc-response.sender parsed))
         (cmd (erc-response.command parsed))
         (tgt (car (erc-response.command-args parsed)))
         (msg (erc-response.contents parsed)))
-    (if (or (erc-ignored-user-p sender-spec)
-            (erc-ignored-reply-p msg tgt proc))
+    (defvar erc-minibuffer-ignored)
+    (defvar erc-ignore-list)
+    (defvar erc-ignore-reply-list)
+    (if (or (and erc-ignore-list (erc-ignored-user-p sender-spec))
+            (and erc-ignore-reply-list (erc-ignored-reply-p msg tgt proc)))
         (when erc-minibuffer-ignored
           (message "Ignored %s from %s to %s" cmd sender-spec tgt))
+      (defvar erc--msg-prop-overrides)
       (let* ((sndr (erc-parse-user sender-spec))
              (nick (nth 0 sndr))
              (login (nth 1 sndr))
@@ -1932,16 +1988,22 @@ add things to `%s' instead."
              (msgp (string= cmd "PRIVMSG"))
              (noticep (string= cmd "NOTICE"))
              ;; S.B. downcase *both* tgt and current nick
-             (privp (erc-current-nick-p tgt))
+             (medown (erc-downcase (erc-current-nick)))
+             (inputp (string= medown (erc-downcase nick)))
+             (privp (string= (erc-downcase tgt) medown))
              (erc--display-context `((erc-buffer-display . ,(intern cmd))
                                      ,@erc--display-context))
-             s buffer
+             (erc--msg-prop-overrides `((erc--tmp) ,@erc--msg-prop-overrides))
+             (erc--speaker-status-prefix-wanted-p nil)
+             (erc-current-message-catalog erc--message-speaker-catalog)
+             s buffer statusmsg cmem-prefix
              fnick)
-        (setf (erc-response.contents parsed) msg)
         (setq buffer (erc-get-buffer (if privp nick tgt) proc))
         ;; Even worth checking for empty target here? (invalid anyway)
         (unless (or buffer noticep (string-empty-p tgt) (eq ?$ (aref tgt 0))
                     (erc-is-message-ctcp-and-not-action-p msg))
+          (defvar erc-receive-query-display)
+          (defvar erc-receive-query-display-defer)
           (if privp
               (when-let ((erc-join-buffer
                           (or (and (not erc-receive-query-display-defer)
@@ -1952,9 +2014,14 @@ add things to `%s' instead."
                 (push `(erc-receive-query-display . ,(intern cmd))
                       erc--display-context)
                 (setq buffer (erc--open-target nick)))
-            ;; A channel buffer has been killed but is still joined.
-            (when erc-ensure-target-buffer-on-privmsg
-              (setq buffer (erc--open-target tgt)))))
+            (cond
+             ;; Target is a channel and contains leading @+ chars.
+             ((and-let* ((trimmed(erc--statusmsg-target tgt)))
+                (setq buffer (erc-get-buffer trimmed proc)
+                      statusmsg (and buffer (substring tgt 0 1)))))
+             ;; A channel buffer has been killed but is still joined.
+             (erc-ensure-target-buffer-on-privmsg
+              (setq buffer (erc--open-target tgt))))))
         (when buffer
           (with-current-buffer buffer
             (when privp (erc--unhide-prompt))
@@ -1963,35 +2030,48 @@ add things to `%s' instead."
             ;; at this point.
             (erc-update-channel-member (if privp nick tgt) nick nick
                                        privp nil nil nil nil nil host login 
nil nil t)
+            (defvar erc--cmem-from-nick-function)
+            (defvar erc-format-nick-function)
+            (defvar erc-show-speaker-membership-status)
+            (defvar erc-speaker-from-channel-member-function)
             (let ((cdata (funcall erc--cmem-from-nick-function
                                   (erc-downcase nick) sndr parsed)))
-              (setq fnick (funcall erc-format-nick-function
-                                   (car cdata) (cdr cdata))))))
+              (setq fnick (funcall erc-speaker-from-channel-member-function
+                                   (car cdata) (cdr cdata))
+                    cmem-prefix (and (or erc--speaker-status-prefix-wanted-p
+                                         erc-show-speaker-membership-status
+                                         inputp)
+                                     (cdr cdata))))))
         (cond
          ((erc-is-message-ctcp-p msg)
-          (setq s (if msgp
+          ;; FIXME explain undefined return values being assigned to `s'.
+          (setq s (if-let ((parsed
+                            (erc--ctcp-response-from-parsed
+                             :parsed parsed :buffer buffer :statusmsg statusmsg
+                             :prefix cmem-prefix :dispname fnick))
+                           (msgp))
                       (erc-process-ctcp-query proc parsed nick login host)
                     (erc-process-ctcp-reply proc parsed nick login host
                                             (match-string 1 msg)))))
          (t
           (setq erc-server-last-peers (cons nick (cdr erc-server-last-peers)))
-          (setq s (erc-format-privmessage
-                   (or fnick nick) msg
-                   ;; If buffer is a query buffer,
-                   ;; format the nick as for a channel.
-                   (and (not (and buffer
-                                  (erc-query-buffer-p buffer)
-                                  erc-format-query-as-channel-p))
-                        privp)
-                   msgp))))
+          (with-current-buffer (or buffer (current-buffer))
+            ;; Re-bind in case either buffer has a local value.
+            (let ((erc-current-message-catalog erc--message-speaker-catalog))
+              (setq s (erc--determine-speaker-message-format-args
+                       nick msg privp msgp inputp statusmsg
+                       cmem-prefix fnick))))))
         (when s
           (if (and noticep privp)
               (progn
+                (push (cons 'erc--msg (car s)) erc--msg-prop-overrides)
+                (setq s (apply #'erc-format-message s))
                 (run-hook-with-args 'erc-echo-notice-always-hook
                                     s parsed buffer nick)
                 (run-hook-with-args-until-success
                  'erc-echo-notice-hook s parsed buffer nick))
-            (erc-display-message parsed nil buffer s)))))))
+            (apply #'erc-display-message parsed nil buffer
+                   (ensure-list s))))))))
 
 (define-erc-response-handler (QUIT)
   "Another user has quit IRC." nil
@@ -2411,6 +2491,7 @@ See `erc-display-server-message'." nil
     (erc-display-message parsed 'notice (erc-get-buffer channel proc)
                          's341 ?n nick ?c channel)))
 
+;; FIXME update or add server user instead when channel is "*".
 (define-erc-response-handler (352)
   "WHO notice." nil
   (pcase-let ((`(,channel ,user ,host ,_server ,nick ,away-flag)
@@ -2476,9 +2557,28 @@ See `erc-display-server-message'." nil
    's391 ?s (cadr (erc-response.command-args parsed))
    ?t (nth 2 (erc-response.command-args parsed))))
 
+;; https://defs.ircdocs.horse/defs/numerics.html#rpl-visiblehost-396
+;; As of ERC 5.6, if the client hasn't yet joined any channels,
+;; there's a good chance a server user for the current nick simply
+;; doesn't exist (and there's not enough info in this reply to create
+;; one).  To fix this, ERC could WHO itself on 372 or similar if it
+;; hasn't yet received a 900.
+(define-erc-response-handler (396)
+  "RPL_VISIBLEHOST or RPL_YOURDISPLAYHOST or RPL_HOSTHIDDEN." nil
+  (pcase-let* ((userhost (cadr (erc-response.command-args parsed)))
+               ;; Behavior blindly copied from event_hosthidden in irssi 1.4.
+               (rejectrx (rx (| (: bot (in ?@ ?: ?-)) (in ?* ?? ?! ?# ?& ?\s)
+                                (: ?- eot))))
+               (`(,_ ,user ,host) (and (not (string-match rejectrx userhost))
+                                       (erc--parse-nuh userhost))))
+    (when host
+      (erc-update-user-nick (erc-current-nick) nil host user)
+      (erc-display-message parsed 'notice 'active 's396 ?s userhost))))
+
 (define-erc-response-handler (401)
   "No such nick/channel." nil
   (let ((nick/channel (cadr (erc-response.command-args parsed))))
+    (defvar erc-whowas-on-nosuchnick)
     (when erc-whowas-on-nosuchnick
       (erc-log (format "cmd: WHOWAS: %s" nick/channel))
       (erc-server-send (format "WHOWAS %s 1" nick/channel)))
@@ -2579,6 +2679,8 @@ See `erc-display-server-message'." nil
   "Channel key needed." nil
   (erc-display-message parsed '(notice error) nil 's475
                        ?c (cadr (erc-response.command-args parsed)))
+  (defvar erc-prompt-for-channel-key)
+  (defvar erc--called-as-input-p)
   (when erc-prompt-for-channel-key
     (let ((channel (cadr (erc-response.command-args parsed)))
           (erc--called-as-input-p t)
diff --git a/lisp/erc/erc-button.el b/lisp/erc/erc-button.el
index e1c10be53f6..d27aa299df2 100644
--- a/lisp/erc/erc-button.el
+++ b/lisp/erc/erc-button.el
@@ -70,6 +70,11 @@
   "ERC button face."
   :group 'erc-faces)
 
+(defface erc-button-nick-default-face '((t :inherit erc-nick-default-face))
+  "Default face for a buttonized nickname."
+  :package-version '(ERC . "5.6")
+  :group 'erc-faces)
+
 (defcustom erc-button-face 'erc-button
   "Face used for highlighting buttons in ERC buffers.
 
@@ -78,8 +83,9 @@ A button is a piece of text that you can activate by pressing
   :type 'face
   :group 'erc-faces)
 
-(defcustom erc-button-nickname-face 'erc-nick-default-face
+(defcustom erc-button-nickname-face 'erc-button-nick-default-face
   "Face used for ERC nickname buttons."
+  :package-version '(ERC . "5.6")
   :type 'face
   :group 'erc-faces)
 
@@ -216,6 +222,9 @@ PAR is a number of a regexp grouping whose text will be 
passed to
   "URL of the EmacsWiki ELisp area."
   :type 'string)
 
+(defvar erc-button-highlight-nick-once '(QUIT PART JOIN)
+  "Messages for which to buttonize only the first nick occurrence.")
+
 (defvar erc-button-keymap
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "RET") #'erc-button-press-button)
@@ -363,7 +372,8 @@ specified by `erc-button-alist'."
   ( nickname-face erc-button-nickname-face :type symbol
     :documentation "Temp `erc-button-nickname-face' while buttonizing.")
   ( mouse-face erc-button-mouse-face :type symbol
-    :documentation "Temp `erc-button-mouse-face' while buttonizing."))
+    :documentation "Function to return possibly cached face.")
+  ( face-cache nil :type (or null function)))
 
 ;; This variable is intended to serve as a "core" to be wrapped by
 ;; (built-in) modules during setup.  It's unclear whether
@@ -382,11 +392,22 @@ be updated at will.")
 
 (defvar-local erc-button--phantom-cmems nil)
 
-(defvar erc-button--fallback-cmem-function #'ignore
+(defvar erc-button--fallback-cmem-function
+  #'erc-button--get-user-from-spkr-prop
   "Function to determine channel member if not found in the usual places.
-Called with DOWNCASED-NICK, NICK, and NICK-BOUNDS when
+Called with DOWNCASED-NICK, NICK, NICK-BOUNDS, and COUNT when
 `erc-button-add-nickname-buttons' cannot find a user object for
-DOWNCASED-NICK in `erc-channel-users' or `erc-server-users'.")
+DOWNCASED-NICK in `erc-channel-users' or `erc-server-users'.
+NICK-BOUNDS is a cons of buffer positions, and COUNT is a number
+incremented with each visit, starting at 1.")
+
+(defun erc-button--get-user-from-spkr-prop (_ _ _ count)
+  "Attempt to obtain an `erc-channel-user' from current \"msg props\".
+But only do so when COUNT is 1, meaning this is the first button
+candidate in the just-inserted message."
+  (and-let* (((= 1 count))
+             (nick (erc--check-msg-prop 'erc--spkr)))
+    (gethash nick erc-channel-users)))
 
 ;; Historical or fictitious users.  As long as these two structs
 ;; remain superficial "subclasses" with the same slots and defaults,
@@ -408,7 +429,7 @@ DOWNCASED-NICK in `erc-channel-users' or 
`erc-server-users'.")
     (puthash downcased (cons user cuser) erc-button--phantom-cmems)
     (cons user cuser)))
 
-(defun erc-button--get-phantom-cmem (down _word _bounds)
+(defun erc-button--get-phantom-cmem (down _word _bounds _count)
   (gethash down erc-button--phantom-cmems))
 
 (define-minor-mode erc-button--phantom-users-mode
@@ -446,37 +467,37 @@ retrieve it during buttonizing via
                           (and erc-button-buttonize-nicks
                                erc-button--modify-nick-function)))
                      (erc-button--extract-form form)))
+             (oncep (if-let ((erc-button-highlight-nick-once)
+                             (c (erc--check-msg-prop 'erc--cmd))
+                             ((memq c erc-button-highlight-nick-once)))
+                        1 0))
              (seen 0))
     (goto-char (point-min))
     (while-let
-        (((erc-forward-word))
+        (((or (zerop seen) (zerop oncep)))
+         ((erc-forward-word))
          (bounds (or (and (= 1 (cl-incf seen)) (erc--get-speaker-bounds))
                      (erc-bounds-of-word-at-point)))
          (word (buffer-substring-no-properties (car bounds) (cdr bounds)))
          (down (erc-downcase word)))
-      (let* ((erc-button-mouse-face erc-button-mouse-face)
-             (erc-button-nickname-face erc-button-nickname-face)
+      (let* ((nick-obj t)
              (cuser (and erc-channel-users
                          (or (gethash down erc-channel-users)
                              (funcall erc-button--fallback-cmem-function
-                                      down word bounds))))
+                                      down word bounds seen))))
              (user (or (and cuser (car cuser))
                        (and erc-server-users (gethash down erc-server-users))))
              (data (list word)))
         (when (or (not (functionp form))
-                  (and-let* ((user)
-                             (obj (funcall form (make-erc-button--nick
-                                                 :bounds bounds :data data
-                                                 :downcased down :user user
-                                                 :cuser (cdr cuser)))))
-                    (setq erc-button-mouse-face ; might be null
-                          (erc-button--nick-mouse-face obj)
-                          erc-button-nickname-face ; might be null
-                          (erc-button--nick-nickname-face obj)
-                          data (erc-button--nick-data obj)
-                          bounds (erc-button--nick-bounds obj))))
+                  (and user
+                       (setq nick-obj (funcall form (make-erc-button--nick
+                                                     :bounds bounds :data data
+                                                     :downcased down :user user
+                                                     :cuser (cdr cuser)))
+                             data (erc-button--nick-data nick-obj)
+                             bounds (erc-button--nick-bounds nick-obj))))
           (erc-button-add-button (car bounds) (cdr bounds) (nth 3 entry)
-                                 'nickp data))))))
+                                 nick-obj data))))))
 
 (defun erc-button-add-buttons-1 (regexp entry)
   "Search through the buffer for matches to ENTRY and add buttons."
@@ -535,13 +556,20 @@ REGEXP is the regular expression which matched for this 
button."
           (move-marker pos (point))))))
   (if nick-p
       (when erc-button-nickname-face
-        (erc-button-add-face from to erc-button-nickname-face))
+        (erc--merge-prop from to 'font-lock-face
+                         (or (and (erc-button--nick-p nick-p)
+                                  (erc-button--nick-nickname-face nick-p))
+                             erc-button-nickname-face)
+                         nil (and (erc-button--nick-p nick-p)
+                                  (erc-button--nick-face-cache nick-p))))
     (when erc-button-face
-      (erc-button-add-face from to erc-button-face)))
+      (erc--merge-prop from to 'font-lock-face erc-button-face)))
   (add-text-properties
    from to
-   (nconc (and erc-button-mouse-face
-               (list 'mouse-face erc-button-mouse-face))
+   (nconc (and-let* ((face (or (and (erc-button--nick-p nick-p)
+                                    (erc-button--nick-mouse-face nick-p))
+                               erc-button-mouse-face)))
+            (list 'mouse-face face))
           (list 'erc-callback fun)
           (list 'keymap erc-button-keymap)
           (list 'rear-nonsticky t)
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index 8daedf9b019..64312e51f41 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -29,9 +29,7 @@
 (defvar erc--casemapping-rfc1459)
 (defvar erc--casemapping-rfc1459-strict)
 (defvar erc-channel-users)
-(defvar erc-dbuf)
 (defvar erc-insert-this)
-(defvar erc-log-p)
 (defvar erc-modules)
 (defvar erc-send-this)
 (defvar erc-server-process)
@@ -51,7 +49,7 @@
 (declare-function widget-type "wid-edit" (widget))
 
 (cl-defstruct erc-input
-  string insertp sendp refoldp)
+  string insertp sendp)
 
 (cl-defstruct (erc--input-split (:include erc-input
                                           (string :read-only)
@@ -59,6 +57,7 @@
                                           (sendp (with-suppressed-warnings
                                                      ((obsolete erc-send-this))
                                                    erc-send-this))))
+  (refoldp nil :type boolean)
   (lines nil :type (list-of string))
   (abortp nil :type (list-of symbol))
   (cmdp nil :type boolean))
@@ -69,8 +68,23 @@
   ;; Buffers
   (buffers nil))
 
-(cl-defstruct (erc-channel-user (:type vector) :named)
-  voice halfop op admin owner
+(cl-defstruct (erc-channel-user (:type vector)
+                                (:constructor
+                                 erc-channel-user--make
+                                 (&key (status 0) (last-message-time nil)))
+                                (:constructor
+                                 make-erc-channel-user
+                                 ( &key voice halfop op admin owner
+                                   last-message-time
+                                   &aux (status (+ (if voice  1 0)
+                                                   (if halfop 2 0)
+                                                   (if op     4 0)
+                                                   (if admin  8 0)
+                                                   (if owner 16 0)))))
+                                :named)
+  "Object containing channel-specific data for a single user."
+  ;; voice halfop op admin owner
+  (status 0 :type integer)
   ;; Last message time (in the form of the return value of
   ;; (current-time)
   ;;
@@ -101,6 +115,23 @@
   (contents "" :type string)
   (tags '() :type list))
 
+(cl-defstruct (erc--ctcp-response
+               (:include erc-response)
+               (:constructor
+                erc--ctcp-response-from-parsed
+                (&key parsed buffer statusmsg prefix dispname
+                      &aux (unparsed (erc-response.unparsed parsed))
+                      (sender (erc-response.sender parsed))
+                      (command (erc-response.command parsed))
+                      (command-args (erc-response.command-args parsed))
+                      (contents (erc-response.contents parsed))
+                      (tags (erc-response.tags parsed)))))
+  "Data for a processed CTCP query or reply."
+  (buffer nil :type (or buffer null))
+  (statusmsg nil :type (or null string))
+  (prefix nil :type (or erc-channel-user null))
+  (dispname nil :type (or string null)))
+
 (cl-defstruct erc--isupport-data
   "Abstract \"class\" for parsed ISUPPORT data.
 For use with the macro `erc--with-isupport-data'."
@@ -458,6 +489,7 @@ nil."
     (if session-buffer
         (progn
           (set-buffer session-buffer)
+          (defvar erc-dbuf)
           (if (not (and erc-dbuf (bufferp erc-dbuf) (buffer-live-p erc-dbuf)))
               (progn
                 (setq erc-dbuf (get-buffer-create
@@ -473,6 +505,9 @@ nil."
           (set-buffer cb))
       (message "ERC: ** %s" string))))
 
+(defvar erc-log-p nil
+  "When non-nil, generate debug messages in an \"*ERC-DEBUG*\" buffer.")
+
 (define-inline erc-log (string)
   "Logs STRING if logging is on (see `erc-log-p')."
   (inline-quote
@@ -488,15 +523,17 @@ Use the CASEMAPPING ISUPPORT parameter to determine the 
style."
                      (_ erc--casemapping-rfc1459))
     (downcase string)))
 
-(define-inline erc-get-channel-user (nick)
-  "Find NICK in the current buffer's `erc-channel-users' hash table."
+(define-inline erc-get-channel-member (nick)
+  "Find NICK in the current buffer's `erc-channel-members' hash table."
   (inline-quote (gethash (erc-downcase ,nick) erc-channel-users)))
+(defalias 'erc-get-channel-user #'erc-get-channel-member)
 
 (define-inline erc-get-server-user (nick)
   "Find NICK in the current server's `erc-server-users' hash table."
   (inline-letevals (nick)
-    (inline-quote (erc-with-server-buffer
-                    (gethash (erc-downcase ,nick) erc-server-users)))))
+    (inline-quote
+     (gethash (erc-downcase ,nick)
+              (erc-with-server-buffer erc-server-users)))))
 
 (defmacro erc--with-dependent-type-match (type &rest features)
   "Massage Custom :type TYPE with :match function that pre-loads FEATURES."
@@ -506,6 +543,60 @@ Use the CASEMAPPING ISUPPORT parameter to determine the 
style."
                              (,(widget-get (widget-convert type) :match) w v))
                     ',(cdr type)))
 
+;; This internal variant exists as a transition aid to avoid
+;; immediately having to reflow lengthy definition lists, like the one
+;; in erc.el.  These sites should switch to using the public macro
+;; when undergoing their next major edit.
+(defmacro erc--define-catalog (name entries)
+  "Define `erc-display-message' formatting templates for NAME, a symbol.
+
+See `erc-define-message-format-catalog' for the meaning of
+ENTRIES, an alist.  Also see `erc-tests-pp-propertized-parts' in
+tests/lisp/erc/erc-tests.el for a convenience command to convert
+a literal string into a sequence of `propertize' forms, which
+are much easier to review and edit."
+  (declare (indent 1))
+  (let (out)
+    (dolist (e entries (cons 'progn (nreverse out)))
+      (push `(defvar ,(intern (format "erc-message-%s-%s" name (car e)))
+               ,(cdr e)
+               ,(let* ((first (format "Message template for key `%s'" (car e)))
+                       (last (format "catalog `%s'." name))
+                       (combined (concat first " in " last)))
+                  (if (< (length combined) 80)
+                      combined
+                    (concat first ".\nFor use with " last))))
+            out))))
+
+(defmacro erc-define-message-format-catalog (language &rest entries)
+  "Define message-formatting templates for LANGUAGE, a symbol.
+Expect ENTRIES to be pairs of (KEY . FORMAT), where KEY is a
+symbol, and FORMAT evaluates to a format string compatible with
+`format-spec'.  Expect modules that only define a handful of
+entries to do so manually, instead of using this macro, so that
+the resulting variables will end up with more useful doc strings."
+  (declare (indent 1))
+  `(erc--define-catalog ,language ,entries))
+
+(defmacro erc--doarray (spec &rest body)
+  "Map over ARRAY, running BODY with VAR bound to iteration element.
+Behave more or less like `seq-doseq', but tailor operations for
+arrays.
+
+\(fn (VAR ARRAY [RESULT]) BODY...)"
+  (declare (indent 1) (debug ((symbolp form &optional form) body)))
+  (let ((array (make-symbol "array"))
+        (len (make-symbol "len"))
+        (i (make-symbol "i")))
+    `(let* ((,array ,(nth 1 spec))
+            (,len (length ,array))
+            (,i 0))
+       (while-let (((< ,i ,len))
+                   (,(car spec) (aref ,array ,i)))
+         ,@body
+         (cl-incf ,i))
+       ,(nth 2 spec))))
+
 (provide 'erc-common)
 
 ;;; erc-common.el ends here
diff --git a/lisp/erc/erc-dcc.el b/lisp/erc/erc-dcc.el
index f05ae41fc51..d12ebd33a86 100644
--- a/lisp/erc/erc-dcc.el
+++ b/lisp/erc/erc-dcc.el
@@ -131,9 +131,8 @@ Looks like:
     (open-network-stream procname buffer addr port
                          :type (and (plist-get entry :secure) 'tls))))
 
-(erc-define-catalog
- 'english
- '((dcc-chat-discarded
+(erc--define-catalog english
+  ((dcc-chat-discarded
     . "DCC: previous chat request from %n (%u@%h) discarded")
    (dcc-chat-ended . "DCC: chat with %n ended %t: %e")
    (dcc-chat-no-request . "DCC: chat request from %n not found")
@@ -714,8 +713,8 @@ It extracts the information about the dcc request and adds 
it to
              (port (match-string 4 query))
              (size (match-string 5 query))
              (sub (substring (match-string 6 query) 0 -4))
-             (secure (seq-contains-p sub ?S #'eq))
-             (turbo (seq-contains-p sub ?T #'eq)))
+             (secure (string-search "S" sub))
+             (turbo (string-search "T" sub)))
         ;; FIXME: a warning really should also be sent
         ;; if the ip address != the host the dcc sender is on.
         (erc-display-message
@@ -1252,14 +1251,16 @@ other client."
 (defun erc-dcc-chat-parse-output (proc str)
   (save-match-data
     (let ((posn 0)
+          (erc--msg-prop-overrides `((erc--spkr . ,erc-dcc-from)))
+          (nick (propertize (erc--speakerize-nick erc-dcc-from)
+                            'font-lock-face 'erc-nick-default-face))
           line)
       (while (string-match "\n" str posn)
         (setq line (substring str posn (match-beginning 0)))
         (setq posn (match-end 0))
         (erc-display-message
          nil nil proc
-         'dcc-chat-privmsg ?n (propertize erc-dcc-from 'font-lock-face
-                                          'erc-nick-default-face) ?m line))
+         'dcc-chat-privmsg ?n nick ?m line))
       (setq erc-dcc-unprocessed-output (substring str posn)))))
 
 (defun erc-dcc-chat-buffer-killed ()
diff --git a/lisp/erc/erc-fill.el b/lisp/erc/erc-fill.el
index 82e881cb71c..16ae5bae8d5 100644
--- a/lisp/erc/erc-fill.el
+++ b/lisp/erc/erc-fill.el
@@ -144,12 +144,14 @@ user-defined functions."
   :package-version '(ERC . "5.6")
   :type 'boolean)
 
-(defcustom erc-fill-line-spacing nil
+(defvar erc-fill-line-spacing nil
   "Extra space between messages on graphical displays.
-Its value should be larger than that of the variable
-`line-spacing', if set.  When unsure, start with 0.5."
-  :package-version '(ERC . "5.6")
-  :type '(choice (const nil) number))
+Its value should probably be larger than that of the variable
+`line-spacing', if non-nil.  When unsure, start with 1.0.  Note
+that as of ERC 5.6, this feature doesn't combine well with the
+`scrolltobottom' module, which is de facto required when using
+the `fill-wrap' filling style.  Users should therefore regard
+this variable as experimental for the time being.")
 
 (defvar-local erc-fill--function nil
   "Internal copy of `erc-fill-function'.
@@ -177,11 +179,10 @@ You can put this on `erc-insert-modify-hook' and/or 
`erc-send-modify-hook'."
           (when-let ((erc-fill-line-spacing)
                      (p (point-min)))
             (widen)
-            (when (or (erc--check-msg-prop 'erc-msg 'msg)
-                      (and-let* ((m (save-excursion
-                                      (forward-line -1)
-                                      (erc--get-inserted-msg-prop 'erc-msg))))
-                        (eq 'msg m)))
+            (when (or (erc--check-msg-prop 'erc--spkr)
+                      (save-excursion
+                        (forward-line -1)
+                        (erc--get-inserted-msg-prop 'erc--spkr)))
               (put-text-property (1- p) p
                                  'line-spacing erc-fill-line-spacing))))))))
 
@@ -190,7 +191,7 @@ You can put this on `erc-insert-modify-hook' and/or 
`erc-send-modify-hook'."
   (save-restriction
     (goto-char (point-min))
     (when-let (((looking-at "^\\(\\S-+\\)"))
-               ((not (erc--check-msg-prop 'erc-msg 'datestamp)))
+               ((not (erc--check-msg-prop 'erc--msg 'datestamp)))
                (nick (match-string 1)))
       (progn
         (let ((fill-column (- erc-fill-column (erc-timestamp-offset)))
@@ -262,9 +263,7 @@ the value of `erc-fill-wrap-visual-keys'."
   "Whether to consolidate consecutive messages from the same speaker.
 When non-nil, ERC omits redundant speaker labels for subsequent
 messages less than a day apart.  To help distinguish between
-merged messages, see related options `erc-fill-line-spacing', for
-graphical displays, and `erc-fill-wrap-merge-indicator' for text
-terminals."
+merged messages, see option `erc-fill-wrap-merge-indicator'."
   :package-version '(ERC . "5.6")
   :type 'boolean)
 
@@ -282,19 +281,25 @@ Only matters when the option `erc-fill-wrap-merge' is 
enabled.
 If the first element is the symbol `pre', ERC uses this option to
 generate a replacement for the speaker's name tag.  If the first
 element is `post', ERC affixes a short string to the end of the
-previous message.  (Note that the latter variant nullifies any
-intervening padding supplied by `erc-fill-line-spacing' and is
-meant to supplant that option in text terminals.)  In either
-case, the second element should be a character, like ?>, and the
-last element a valid face.  In special cases, you may also
-specify a cons of `pre'/`post' and a string, which tells ERC you
-know what you're doing and not to manage the process for you.  If
-unsure, try either of the first two presets, both of which
-replace a continued speaker's name with a dot-product-like glyph
-in `shadow' face.  Note that this option is still experimental,
-and changing its value mid-session is not yet supported (though,
-if you must, make sure to run \\[erc-fill-wrap-refill-buffer]
-afterward)."
+previous message.  In either case, the second element should be a
+character, like ?>, and the last element a valid face.  In
+special cases, you may also specify a cons of either
+aforementioned symbol and a string, which tells ERC not to manage
+the process for you.  If unsure, try either of the first two
+presets, both of which replace a continued speaker's name with a
+dot-product-like character in a `shadow'-like face.
+
+Note that as of ERC 5.6, this option is still experimental, and
+changing its value mid-session is not yet supported (though, if
+you must, make sure to run \\[erc-fill-wrap-refill-buffer]
+afterward).  Also note that users on versions of Emacs older than
+29.2 may experience a \"glitching\" effect when point resides on
+a \"merged\" message occupying the first or last line in a
+window.  If that happens, try replacing `top' with the integer 1
+in the option `recenter-positions' while also maybe adjusting
+`scroll-margin' and/or `scroll-preserve-screen-position' to avoid
+\"dragging\" point when issuing a `scroll-up' or `scroll-down'
+command."
   :package-version '(ERC . "5.6")
   :type
   '(choice (const nil)
@@ -469,12 +474,12 @@ cycling between logical- and screen-line oriented command
 movement.  Similarly, use \\[erc-fill-wrap-refill-buffer] to fix
 alignment problems after running certain commands, like
 `text-scale-adjust'.  Also see related stylistic options
-`erc-fill-line-spacing', `erc-fill-wrap-merge', and
-`erc-fill-wrap-merge-indicator'.  Hint: in narrow windows, where
-is space tight, try setting `erc-fill-static-center' to 1.  And
-if you also use the option `erc-fill-wrap-merge-indicator', set
-that to value-menu item \"Leading MIDDLE DOT (U+00B7) sans gap\"
-or one of the various \"trailing\" items.
+`erc-fill-wrap-merge', and `erc-fill-wrap-merge-indicator'.
+\(Hint: in narrow windows, where is space tight, try setting
+`erc-fill-static-center' to 1.  And if you also use the option
+`erc-fill-wrap-merge-indicator', set that to value-menu item
+\"Leading MIDDLE DOT sans gap\" or one of the various
+\"trailing\" items.)
 
 This module imposes various restrictions on the appearance of
 timestamps.  Most notably, it insists on displaying them in the
@@ -547,43 +552,38 @@ behavior of taking the length from the first \"word\".  
This
 variable can be converted to a public one if needed by third
 parties.")
 
-(defvar-local erc-fill--wrap-last-msg nil)
-(defvar erc-fill--wrap-max-lull (* 24 60 60))
+(defvar-local erc-fill--wrap-last-msg nil "Marker for merging speakers.")
+(defvar erc-fill--wrap-max-lull (* 24 60 60) "Max secs for merging speakers.")
 
 (defun erc-fill--wrap-continued-message-p ()
   "Return non-nil when the current speaker hasn't changed.
-That is, indicate whether the text just inserted is from the same
-sender as that of the previous \"PRIVMSG\"."
-  (and
-   (not (erc--check-msg-prop 'erc-ephemeral))
-   (progn ; preserve blame for now, unprogn on next major change
-     (prog1
-         (and-let*
-             ((m (or erc-fill--wrap-last-msg
-                     (setq erc-fill--wrap-last-msg (point-min-marker))
-                     nil))
-              ((< (1+ (point-min)) (- (point) 2)))
-              (props (save-restriction
-                       (widen)
-                       (and-let*
-                           (((eq 'msg (get-text-property m 'erc-msg)))
-                            ((not (eq (get-text-property m 'erc-ctcp)
-                                      'ACTION)))
-                            ((not (invisible-p m)))
-                            (spr (next-single-property-change m 'erc-speaker)))
-                         (cons (get-text-property m 'erc-ts)
-                               (get-text-property spr 'erc-speaker)))))
-              (ts (pop props))
-              (props)
-              ((not (time-less-p (erc-stamp--current-time) ts)))
-              ((time-less-p (time-subtract (erc-stamp--current-time) ts)
-                            erc-fill--wrap-max-lull))
-              ;; Assume presence of leading angle bracket or hyphen.
-              (speaker (next-single-property-change (point-min) 'erc-speaker))
-              ((not (erc--check-msg-prop 'erc-ctcp 'ACTION)))
-              (nick (get-text-property speaker 'erc-speaker))
-              ((erc-nick-equal-p props nick))))
-       (set-marker erc-fill--wrap-last-msg (point-min))))))
+But only if the `erc--msg' text property also hasn't.  That is,
+indicate whether the chat message just inserted is from the same
+person as the prior one and is formatted in the same manner.  As
+a side effect, advance `erc-fill--wrap-last-msg' unless the
+message has been marked `erc--ephemeral'."
+  (and-let*
+      (((not (erc--check-msg-prop 'erc--ephemeral)))
+       ;; Always set/move `erc-fill--wrap-last-msg' from here on down.
+       (m (or (and erc-fill--wrap-last-msg
+                   (prog1 (marker-position erc-fill--wrap-last-msg)
+                     (set-marker erc-fill--wrap-last-msg (point-min))))
+              (ignore (setq erc-fill--wrap-last-msg (point-min-marker)))))
+       ((>= (point) 4)) ; skip the first message
+       (props (save-restriction
+                (widen)
+                (and-let* ((speaker (get-text-property m 'erc--spkr))
+                           (type (get-text-property m 'erc--msg))
+                           ((not (invisible-p m))))
+                  (list (get-text-property m 'erc--ts) type speaker))))
+       (ts (nth 0 props))
+       (type (nth 1 props))
+       (speaker (nth 2 props))
+       ((not (time-less-p (erc-stamp--current-time) ts)))
+       ((time-less-p (time-subtract (erc-stamp--current-time) ts)
+                     erc-fill--wrap-max-lull))
+       ((erc--check-msg-prop 'erc--msg type))
+       ((erc-nick-equal-p speaker (erc--check-msg-prop 'erc--spkr))))))
 
 (defun erc-fill--wrap-measure (beg end)
   "Return display spec width for inserted region between BEG and END.
@@ -666,12 +666,12 @@ See `erc-fill-wrap-mode' for details."
     (goto-char (point-min))
     (let ((len (or (and erc-fill--wrap-length-function
                         (funcall erc-fill--wrap-length-function))
-                   (and-let* ((msg-prop (erc--check-msg-prop 'erc-msg))
+                   (and-let* ((msg-prop (erc--check-msg-prop 'erc--msg))
                               ((not (eq msg-prop 'unknown))))
                      (when-let ((e (erc--get-speaker-bounds))
                                 (b (pop e))
                                 ((or erc-fill--wrap-action-dedent-p
-                                     (not (erc--check-msg-prop 'erc-ctcp
+                                     (not (erc--check-msg-prop 'erc--ctcp
                                                                'ACTION)))))
                        (goto-char e))
                      (skip-syntax-forward "^-")
@@ -744,16 +744,19 @@ With REPAIRP, destructively fill gaps and re-merge 
speakers."
       (remove-text-properties beg (1+ end) '(line-prefix nil wrap-prefix nil))
       (when-let ((repairp)
                  (dbeg (text-property-not-all beg end 'display nil))
-                 ((get-text-property (1+ dbeg) 'erc-speaker))
+                 ((get-text-property (1+ dbeg) 'erc--speaker))
                  (dval (get-text-property dbeg 'display))
                  ((equal "" dval)))
         (remove-text-properties
          dbeg (text-property-not-all dbeg end 'display dval) '(display)))
-      (let* ((pos (if (eq 'date-left (get-text-property beg 'erc-stamp-type))
-                      (field-beginning beg)
+      ;; This "should" work w/o `front-sticky' and `rear-nonsticky'.
+      (let* ((pos (if-let (((eq 'erc-timestamp (field-at-pos beg)))
+                           (b (field-beginning beg))
+                           ((eq 'datestamp (get-text-property b 'erc--msg))))
+                      b
                     beg))
              (erc--msg-props (map-into (text-properties-at pos) 'hash-table))
-             (erc-stamp--current-time (gethash 'erc-ts erc--msg-props)))
+             (erc-stamp--current-time (gethash 'erc--ts erc--msg-props)))
         (save-restriction
           (narrow-to-region beg (1+ end))
           (let ((erc-fill--wrap-last-msg erc-fill--wrap-rejigger-last-message))
diff --git a/lisp/erc/erc-goodies.el b/lisp/erc/erc-goodies.el
index 6c8ec567bd9..e10f047b187 100644
--- a/lisp/erc/erc-goodies.el
+++ b/lisp/erc/erc-goodies.el
@@ -578,7 +578,7 @@ Do nothing if the variable `erc-command-indicator' is nil."
       (let ((insert-position (marker-position (goto-char erc-insert-marker)))
             (erc--msg-props (or erc--msg-props
                                 (let ((ovs erc--msg-prop-overrides))
-                                  (map-into `((erc-msg . slash-cmd)
+                                  (map-into `((erc--msg . slash-cmd)
                                               ,@(reverse ovs))
                                             'hash-table)))))
         (when-let ((string (erc-command-indicator))
diff --git a/lisp/erc/erc-netsplit.el b/lisp/erc/erc-netsplit.el
index 5dd11ab1869..076e1f0254b 100644
--- a/lisp/erc/erc-netsplit.el
+++ b/lisp/erc/erc-netsplit.el
@@ -41,7 +41,7 @@ netsplits, so that it can filter the JOIN messages on a 
netjoin too."
 ;;;###autoload(autoload 'erc-netsplit-mode "erc-netsplit")
 (define-erc-module netsplit nil
   "This mode hides quit/join messages if a netsplit occurs."
-  ((erc-netsplit-install-message-catalogs)
+  ( ; FIXME delete newline on next edit
    (add-hook 'erc-server-JOIN-functions #'erc-netsplit-JOIN)
    (add-hook 'erc-server-MODE-functions #'erc-netsplit-MODE)
    (add-hook 'erc-server-QUIT-functions #'erc-netsplit-QUIT)
@@ -85,13 +85,22 @@ where FIRST-JOIN is t or nil, depending on whether or not 
the first
 join from that split has been detected or not.")
 
 (defun erc-netsplit-install-message-catalogs ()
+  (declare (obsolete "defined at top level in erc-netsplit.el" "30.1"))
+  (with-suppressed-warnings ((obsolete erc-define-catalog)) ; indentation
   (erc-define-catalog
    'english
    '((netsplit        . "netsplit: %s")
      (netjoin         . "netjoin: %s, %N were split")
      (netjoin-done     . "netjoin: All lost souls are back!")
      (netsplit-none    . "No netsplits in progress")
-     (netsplit-wholeft . "split: %s missing: %n %t"))))
+     (netsplit-wholeft . "split: %s missing: %n %t"))))) ; indentation
+
+(erc-define-message-format-catalog english
+  (netsplit . "netsplit: %s")
+  (netjoin . "netjoin: %s, %N were split")
+  (netjoin-done . "netjoin: All lost souls are back!")
+  (netsplit-none . "No netsplits in progress")
+  (netsplit-wholeft . "split: %s missing: %n %t"))
 
 (defun erc-netsplit-JOIN (proc parsed)
   "Show/don't show rejoins."
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index f168c90df65..694f56ed0d5 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -42,16 +42,12 @@
 
 (defvar erc--target)
 (defvar erc-insert-marker)
-(defvar erc-kill-buffer-hook)
-(defvar erc-kill-server-hook)
 (defvar erc-modules)
 (defvar erc-rename-buffers)
 (defvar erc-reuse-buffers)
 (defvar erc-server-announced-name)
 (defvar erc-server-connected)
-(defvar erc-server-parameters)
 (defvar erc-server-process)
-(defvar erc-session-server)
 
 (declare-function erc--get-isupport-entry "erc-backend" (key &optional single))
 (declare-function erc-buffer-filter "erc" (predicate &optional proc))
@@ -1229,6 +1225,8 @@ Use the server parameter NETWORK if provided, otherwise 
parse the
 server name and search for a match in `erc-networks-alist'."
   ;; The server made it easy for us and told us the name of the NETWORK
   (declare (obsolete "maybe see `erc-networks--determine'" "29.1"))
+  (defvar erc-server-parameters)
+  (defvar erc-session-server)
   (let ((network-name (cdr (assoc "NETWORK" erc-server-parameters))))
     (if network-name
        (intern network-name)
@@ -1381,6 +1379,8 @@ already been copied over to the current, replacement 
buffer.")
 (defun erc-networks--copy-over-server-buffer-contents (existing name)
   "Kill off existing server buffer after copying its contents.
 Must be called from the replacement buffer."
+  (defvar erc-kill-buffer-hook)
+  (defvar erc-kill-server-hook)
   ;; ERC expects `erc-open' to be idempotent when setting up local
   ;; vars and other context properties for a new identity.  Thus, it's
   ;; unlikely we'll have to copy anything else over besides text.  And
@@ -1586,14 +1586,29 @@ return the host alone sans URL formatting (for 
compatibility)."
   '((pals Libera.Chat ("kensanata" "shapr" "anti\\(fuchs\\|gone\\)"))
     (format-nick-function (Libera.Chat "#emacs") erc-format-@nick))
   "Experimental: Alist of configuration options.
+
+WARNING: this variable is a vestige from a long-abandoned
+experiment.  ERC may redefine it using the same name for any
+purpose at any time.
+
 The format is (VARNAME SCOPE VALUE) where
 VARNAME is a symbol identifying the configuration option,
 SCOPE is either a symbol which identifies an entry from
   `erc-networks-alist' or a list (NET TARGET) where NET is a network symbol and
   TARGET is a string identifying the channel/query target.
 VALUE is the options value.")
+(make-obsolete-variable 'erc-settings
+                        "temporarily deprecated for later repurposing" "30.1")
 
 (defun erc-get (var &optional net target)
+  "Retrieve configuration values from `erc-settings'.
+
+WARNING: this function is a non-functioning remnant from a
+long-abandoned experiment.  ERC may redefine it using the same
+name for any purpose at any time.
+
+\(fn &rest UNKNOWN)"
+  (declare (obsolete "temporarily deprecated for later repurposing" "30.1"))
   (let ((items erc-settings)
        elt val)
     (while items
diff --git a/lisp/erc/erc-nicks.el b/lisp/erc/erc-nicks.el
index fcd3afdbbc4..b46c5d43cd7 100644
--- a/lisp/erc/erc-nicks.el
+++ b/lisp/erc/erc-nicks.el
@@ -173,6 +173,20 @@ adding extra characters or padding, for example, with 
something
 like \"@%-012n\"."
   :type 'string)
 
+(defcustom erc-nicks-track-faces 'prioritize
+  "Show nick faces in the `track' module's portion of the mode line.
+A value of nil means don't show nick faces at all.  A value of
+`defer' means have `track' consider nick faces only after those
+ranked faces in `erc-track-faces-normal-list'.  This has the
+effect of \"alternating\" between a ranked \"normal\" and a nick.
+The value `prioritize' means have `track' consider nick faces to
+be \"normal\" unless the current speaker is the same as the
+previous one, in which case pretend the value is `defer'.  Like
+most options in this module, updating the value mid-session is
+not officially supported, although cycling \\[erc-nicks-mode] may
+be worth a shot."
+  :type '(choice (const nil) (const defer) (const prioritize)))
+
 (defvar erc-nicks--max-skip-search 3 ; make this an option?
   "Max number of faces to visit when testing `erc-nicks-skip-faces'.")
 
@@ -195,6 +209,7 @@ Keys are nonempty strings but need not be valid nicks.")
 
 (defvar help-xref-stack)
 (defvar help-xref-stack-item)
+(defvar erc-track--normal-faces)
 
 ;; https://stackoverflow.com/questions/596216#answer-56678483
 (defun erc-nicks--get-luminance (color)
@@ -454,7 +469,9 @@ Favor a custom erc-nicks-NICK@NETWORK-face when defined."
           (put new-face 'erc-nicks--nick nick)
           (put new-face 'erc-nicks--netid erc-networks--id)
           (put new-face 'erc-nicks--key key)
-          (face-spec-set new-face `((t :foreground ,color)) 'face-defface-spec)
+          (face-spec-set new-face `((t :foreground ,color
+                                       :inherit ,erc-nicks-backing-face))
+                         'face-defface-spec)
           (set-face-documentation
            new-face (format "Internal face for %s on %s." nick (erc-network)))
           (puthash nick new-face table)))))
@@ -503,12 +520,8 @@ Abandon search after examining LIMIT faces."
              ((not (and base-face
                         (erc-nicks--skip-p base-face erc-nicks-skip-faces
                                            erc-nicks--max-skip-search))))
-             (key (erc-nicks--gen-key-from-format-spec trimmed))
-             (out (erc-nicks--get-face trimmed key)))
-    (if (or (null erc-nicks-backing-face)
-            (eq base-face erc-nicks-backing-face))
-        out
-      (cons out (erc-list erc-nicks-backing-face)))))
+             (key (erc-nicks--gen-key-from-format-spec trimmed)))
+    (erc-nicks--get-face trimmed key)))
 
 (defun erc-nicks--highlight-button (nick-object)
   "Possibly add face to `erc-button--nick-user' NICK-OBJECT."
@@ -518,7 +531,12 @@ Abandon search after examining LIMIT faces."
                                 'font-lock-face))
        (nick (erc-server-user-nickname (erc-button--nick-user nick-object)))
        (out (erc-nicks--highlight nick face)))
-    (setf (erc-button--nick-nickname-face nick-object) out))
+    (setf (erc-button--nick-nickname-face nick-object) out
+          ;;
+          (erc-button--nick-face-cache nick-object)
+          (and erc-nicks-track-faces
+               (bound-and-true-p erc-track--normal-faces)
+               #'erc-nicks--remember-face-for-track)))
   nick-object)
 
 (define-erc-module nicks nil
@@ -561,6 +579,8 @@ Abandon search after examining LIMIT faces."
        erc-nicks--face-table (make-hash-table :test #'equal)))
    (setf (alist-get "Edit face" erc-button--nick-popup-alist nil nil #'equal)
          #'erc-nicks-customize-face)
+   (erc-nicks--setup-track-integration)
+   (add-hook 'erc-track-mode #'erc-nicks--setup-track-integration 50 t)
    (advice-add 'widget-create-child-and-convert :filter-args
                #'erc-nicks--redirect-face-widget-link))
   ((kill-local-variable 'erc-nicks--face-table)
@@ -572,8 +592,12 @@ Abandon search after examining LIMIT faces."
    (kill-local-variable 'erc-nicks--downcased-skip-nicks)
    (when (fboundp 'erc-button--phantom-users-mode)
      (erc-button--phantom-users-mode -1))
+   (remove-function (local 'erc-track--face-reject-function)
+                    #'erc-nicks--reject-uninterned-faces)
    (remove-function (local 'erc-button--modify-nick-function)
                     #'erc-nicks--highlight-button)
+   (remove-function (local 'erc-track--alt-normals-function)
+                    #'erc-nicks--check-normals)
    (setf (alist-get "Edit face"
                     erc-button--nick-popup-alist nil 'remove #'equal)
          nil)
@@ -693,6 +717,58 @@ Expect PREFIX to be something like \"ansi-color-\" or 
\"font-lock-\"."
                  (color (face-foreground face)))
         (push color out)))))
 
+(defun erc-nicks--reject-uninterned-faces (candidate)
+  "Remove own faces from CANDIDATE if it's a combination of faces."
+  (while-let ((next (car-safe candidate))
+              ((facep next))
+              ((not (intern-soft next))))
+    (setq candidate (cdr candidate)))
+  (if (and (consp candidate) (not (cdr candidate))) (car candidate) candidate))
+
+(define-inline erc-nicks--oursp (face)
+  (inline-quote
+   (and-let* ((sym (car-safe ,face))
+              ((symbolp sym))
+              ((get sym 'erc-nicks--key)))
+     sym)))
+
+(defun erc-nicks--check-normals (current contender contenders normals)
+  "Return a viable `nicks'-owned face from NORMALS in CONTENDERS.
+But only do so if the CURRENT face is also one of ours and in
+NORMALS and if the highest ranked CONTENDER among new faces is
+`erc-default-face', the lowest ranking default priority face."
+  (and-let* (((eq contender 'erc-default-face))
+             ((or (null current) (gethash current normals)))
+             (spkr (or (null current) (erc-nicks--oursp current))))
+    (catch 'contender
+      (dolist (candidate (cdr contenders) contender)
+        (when-let (((not (equal candidate current)))
+                   ((gethash candidate normals))
+                   (s (erc-nicks--oursp candidate))
+                   ((not (eq s spkr))))
+          (throw 'contender candidate))))))
+
+(defun erc-nicks--setup-track-integration ()
+  "Restore traditional \"alternating normal\" face functionality to mode-line."
+  (when (bound-and-true-p erc-track-mode)
+    (pcase erc-nicks-track-faces
+      ;; Variant `defer' is handled elsewhere.
+      ('prioritize
+       (add-function :override (local 'erc-track--alt-normals-function)
+                     #'erc-nicks--check-normals))
+      ('nil
+       (add-function :override (local 'erc-track--face-reject-function)
+                     #'erc-nicks--reject-uninterned-faces)))))
+
+(defun erc-nicks--remember-face-for-track (face)
+  "Add FACE to local hash table maintained by `track' module."
+  (or (gethash face erc-track--normal-faces)
+      (if-let ((sym (or (car-safe face) face))
+               ((symbolp sym))
+               ((get sym 'erc-nicks--key)))
+          (puthash face face erc-track--normal-faces)
+        face)))
+
 (provide 'erc-nicks)
 
 ;;; erc-nicks.el ends here
diff --git a/lisp/erc/erc-notify.el b/lisp/erc/erc-notify.el
index cf7ffbb40d7..1aa5bc34f33 100644
--- a/lisp/erc/erc-notify.el
+++ b/lisp/erc/erc-notify.el
@@ -30,7 +30,6 @@
 ;;; Code:
 
 (require 'erc)
-(require 'erc-networks)
 (eval-when-compile (require 'pcomplete))
 
 ;;;; Customizable variables
@@ -78,12 +77,14 @@ strings."
 ;;;; Setup
 
 (defun erc-notify-install-message-catalogs ()
-  (erc-define-catalog
-   'english
-   '((notify_current . "Notified people online: %l")
-     (notify_list    . "Current notify list: %l")
-     (notify_on      . "Detected %n on IRC network %m")
-     (notify_off     . "%n has left IRC network %m"))))
+  (declare (obsolete "defined at top level in erc-notify.el" "30.1"))
+  (with-suppressed-warnings ((obsolete erc-define-catalog))
+    (erc-define-catalog
+     'english
+     '((notify-current . "Notified people online: %l")
+       (notify-list    . "Current notify list: %l")
+       (notify-on      . "Detected %n on IRC network %m")
+       (notify-off     . "%n has left IRC network %m")))))
 
 ;;;###autoload(autoload 'erc-notify-mode "erc-notify" nil t)
 (define-erc-module notify nil
@@ -119,14 +120,14 @@ changes."
             (run-hook-with-args 'erc-notify-signon-hook server (car new-list))
             (erc-display-message
              parsed 'notice proc
-             'notify_on ?n (car new-list) ?m (erc-network-name)))
+              'notify-on ?n (car new-list) ?m (erc-network-name)))
           (setq new-list (cdr new-list)))
         (while old-list
           (when (not (erc-member-ignore-case (car old-list) ison-list))
             (run-hook-with-args 'erc-notify-signoff-hook server (car old-list))
             (erc-display-message
              parsed 'notice proc
-             'notify_off ?n (car old-list) ?m (erc-network-name)))
+              'notify-off ?n (car old-list) ?m (erc-network-name)))
           (setq old-list (cdr old-list)))
         (setq erc-last-ison ison-list)
         t)))
@@ -136,8 +137,8 @@ changes."
 
 (defun erc-notify-JOIN (proc parsed)
   "Check if channel joiner is on `erc-notify-list' and not on `erc-last-ison'.
-If this condition is satisfied, produce a notify_on message and add the nick
-to `erc-last-ison' to prevent any further notifications."
+When that's the case, produce a `notify-on' message and add the
+nick to `erc-last-ison' to prevent any further notifications."
   (let ((nick (erc-extract-nick (erc-response.sender parsed))))
     (when (and (erc-member-ignore-case nick erc-notify-list)
               (not (erc-member-ignore-case nick erc-last-ison)))
@@ -147,13 +148,13 @@ to `erc-last-ison' to prevent any further notifications."
                          nick)
       (erc-display-message
        parsed 'notice proc
-       'notify_on ?n nick ?m (erc-network-name)))
+       'notify-on ?n nick ?m (erc-network-name)))
     nil))
 
 (defun erc-notify-NICK (proc parsed)
   "Check if new nick is on `erc-notify-list' and not on `erc-last-ison'.
-If this condition is satisfied, produce a notify_on message and add the nick
-to `erc-last-ison' to prevent any further notifications."
+When that's the case, produce a `notify-on' message and add the
+nick to `erc-last-ison' to prevent any further notifications."
   (let ((nick (erc-response.contents parsed)))
     (when (and (erc-member-ignore-case nick erc-notify-list)
               (not (erc-member-ignore-case nick erc-last-ison)))
@@ -163,13 +164,13 @@ to `erc-last-ison' to prevent any further notifications."
                          nick)
       (erc-display-message
        parsed 'notice proc
-       'notify_on ?n nick ?m (erc-network-name)))
+       'notify-on ?n nick ?m (erc-network-name)))
     nil))
 
 (defun erc-notify-QUIT (proc parsed)
   "Check if quitter is on `erc-notify-list' and on `erc-last-ison'.
-If this condition is satisfied, produce a notify_off message and remove the
-nick from `erc-last-ison' to prevent any further notifications."
+When that's the case, insert a `notify-off' message and remove
+the nick from `erc-last-ison' to prevent further notifications."
   (let ((nick (erc-extract-nick (erc-response.sender parsed))))
     (when (and (erc-member-ignore-case nick erc-notify-list)
               (erc-member-ignore-case nick erc-last-ison))
@@ -183,7 +184,7 @@ nick from `erc-last-ison' to prevent any further 
notifications."
                          nick)
       (erc-display-message
        parsed 'notice proc
-       'notify_off ?n nick ?m (erc-network-name)))
+       'notify-off ?n nick ?m (erc-network-name)))
     nil))
 
 ;;;; User level command
@@ -193,6 +194,12 @@ nick from `erc-last-ison' to prevent any further 
notifications."
   "Change `erc-notify-list' or list current notify-list members online.
 Without args, list the current list of notified people online,
 with args, toggle notify status of people."
+  (unless erc-notify-mode
+    (erc-notify-mode +1)
+    (erc-button--display-error-notice-with-keys
+     (current-buffer)
+     "Command /NOTIFY requires the `notify' module. Enabling now. Add `notify'"
+     " to `erc-modules' before next starting ERC to silence this message."))
   (cond
    ((null args)
     ;; Print current notified people (online)
@@ -202,11 +209,12 @@ with args, toggle notify status of people."
           nil 'notice 'active "No ison-list yet!")
        (erc-display-message
         nil 'notice 'active
-        'notify_current ?l ison))))
+         'notify-current ?l ison))))
    ((string= (car args) "-l")
-    (erc-display-message nil 'notice 'active
-                        'notify_list ?l (mapconcat #'identity erc-notify-list
-                                                   " ")))
+    (let ((list (if erc-notify-list
+                    (mapconcat #'identity erc-notify-list " ")
+                  "(empty)")))
+      (erc-display-message nil 'notice 'active 'notify-list ?l list)))
    (t
     (while args
       (if (erc-member-ignore-case (car args) erc-notify-list)
@@ -225,23 +233,34 @@ with args, toggle notify status of people."
        (setq erc-notify-list (cons (erc-string-no-properties (car args))
                                    erc-notify-list)))
       (setq args (cdr args)))
-    (erc-display-message
-     nil 'notice 'active
-     'notify_list ?l (mapconcat #'identity erc-notify-list " "))))
+    (erc-cmd-NOTIFY "-l")))
   t)
 
-(autoload 'pcomplete-erc-all-nicks "erc-pcomplete")
-
 ;; "--" is not a typo.
 (declare-function pcomplete--here "pcomplete"
                  (&optional form stub paring form-only))
+(declare-function pcomplete-erc-all-nicks "erc-pcomplete"
+                  (&optional postfix))
 
 ;;;###autoload
 (defun pcomplete/erc-mode/NOTIFY ()
-  (require 'pcomplete)
-  (pcomplete-here (pcomplete-erc-all-nicks)))
-
-(erc-notify-install-message-catalogs)
+  (require 'erc-pcomplete)
+  (pcomplete-here (append erc-notify-list (pcomplete-erc-all-nicks))))
+
+(define-obsolete-variable-alias 'erc-message-english-notify_on
+  'erc-message-english-notify-on "30.1")
+(define-obsolete-variable-alias 'erc-message-english-notify_off
+  'erc-message-english-notify-off "30.1")
+(define-obsolete-variable-alias 'erc-message-english-notify_list
+  'erc-message-english-notify-list "30.1")
+(define-obsolete-variable-alias 'erc-message-english-notify_current
+  'erc-message-english-notify-current "30.1")
+
+(erc-define-message-format-catalog english
+  (notify-current . "Notified people online: %l")
+  (notify-list . "Current notify list: %l")
+  (notify-on . "Detected %n on IRC network %m")
+  (notify-off . "%n has left IRC network %m"))
 
 (provide 'erc-notify)
 
diff --git a/lisp/erc/erc-page.el b/lisp/erc/erc-page.el
index a94678e5132..2e5974bd22e 100644
--- a/lisp/erc/erc-page.el
+++ b/lisp/erc/erc-page.el
@@ -42,7 +42,8 @@
   "Process CTCP PAGE requests from IRC."
   nil nil)
 
-(erc-define-catalog-entry 'english 'CTCP-PAGE "Page from %n (%u@%h): %m")
+(defvar erc-message-english-CTCP-PAGE "Page from %n (%u@%h): %m"
+  "English template for a CTCP PAGE message.")
 
 (defcustom erc-page-function nil
   "A function to process a \"page\" request.
diff --git a/lisp/erc/erc-sasl.el b/lisp/erc/erc-sasl.el
index c6922b1b26b..8ecce7aef31 100644
--- a/lisp/erc/erc-sasl.el
+++ b/lisp/erc/erc-sasl.el
@@ -305,9 +305,8 @@ If necessary, pass PROMPT to `read-passwd'."
                        (| eot ",")))
                   (downcase offered)))
 
-(erc-define-catalog
- 'english
- '((s902 . "ERR_NICKLOCKED nick %n unavailable: %s")
+(erc--define-catalog english
+  ((s902 . "ERR_NICKLOCKED nick %n unavailable: %s")
    (s904 . "ERR_SASLFAIL (authentication failed) %s")
    (s905 . "ERR SASLTOOLONG (credentials too long) %s")
    (s906 . "ERR_SASLABORTED (authentication aborted) %s")
diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el
index 47c59f76b5c..1133b2416bb 100644
--- a/lisp/erc/erc-services.el
+++ b/lisp/erc/erc-services.el
@@ -169,7 +169,7 @@ You can also use \\[erc-nickserv-identify-mode] to change 
modes."
   :type 'boolean)
 
 (defcustom erc-use-auth-source-for-nickserv-password nil
-  "Query auth-source for a password when identifiying to NickServ.
+  "Query auth-source for a password when identifying to NickServ.
 Passwords from `erc-nickserv-passwords' take precedence.  See
 function `erc-nickserv-get-password'."
   :version "28.1"
diff --git a/lisp/erc/erc-sound.el b/lisp/erc/erc-sound.el
index 083d72805df..aaa2e059070 100644
--- a/lisp/erc/erc-sound.el
+++ b/lisp/erc/erc-sound.el
@@ -63,7 +63,8 @@ and play sound files as requested."
   ((remove-hook 'erc-ctcp-query-SOUND-hook #'erc-ctcp-query-SOUND)
    (define-key erc-mode-map "\C-c\C-s" #'undefined)))
 
-(erc-define-catalog-entry 'english 'CTCP-SOUND "%n (%u@%h) plays %s:%m")
+(defvar erc-message-english-CTCP-SOUND "%n (%u@%h) plays %s:%m"
+  "English template for a CTCP SOUND message.")
 
 (defcustom erc-play-sound t
   "Play sounds when you receive CTCP SOUND requests."
diff --git a/lisp/erc/erc-speedbar.el b/lisp/erc/erc-speedbar.el
index 93be7b9f074..90d7376fc0c 100644
--- a/lisp/erc/erc-speedbar.el
+++ b/lisp/erc/erc-speedbar.el
@@ -319,9 +319,7 @@ a list of four items: the userhost, the GECOS, the current
         (info (erc-server-user-info user))
         (login (erc-server-user-login user))
         (name (erc-server-user-full-name user))
-        (voice (and cuser (erc-channel-user-voice cuser)))
-        (op (and cuser (erc-channel-user-op cuser)))
-        (nick-str (concat (if op "@" "") (if voice "+" "") nick))
+         (nick-str (concat (erc-get-channel-membership-prefix cuser) nick))
         (finger (concat login (when (or login host) "@") host))
          (sbtoken (list finger name info (buffer-name buffer))))
     (if (or login host name info) ; we want to be expandable
diff --git a/lisp/erc/erc-stamp.el b/lisp/erc/erc-stamp.el
index e6a8f36c332..9ca3ea320a0 100644
--- a/lisp/erc/erc-stamp.el
+++ b/lisp/erc/erc-stamp.el
@@ -212,7 +212,7 @@ the stamp passed to `erc-insert-timestamp-function'.")
 
 (cl-defgeneric erc-stamp--current-time ()
   "Return a lisp time object to associate with an IRC message.
-This becomes the message's `erc-ts' text property."
+This becomes the message's `erc--ts' text property."
   (erc-compat--current-lisp-time))
 
 (cl-defmethod erc-stamp--current-time :around ()
@@ -249,10 +249,10 @@ or `erc-send-modify-hook'."
             ;; FIXME on major version bump, make this `erc-' prefixed.
             (if invisible `(timestamp ,@(ensure-list invisible)) 'timestamp))
            (skipp (or (and erc-stamp--skip-when-invisible invisible)
-                      (erc--check-msg-prop 'erc-ephemeral)))
+                      (erc--check-msg-prop 'erc--ephemeral)))
            (erc-stamp--current-time ct))
       (when erc--msg-props
-        (puthash 'erc-ts ct erc--msg-props))
+        (puthash 'erc--ts ct erc--msg-props))
       (unless skipp
         (funcall erc-insert-timestamp-function
                  (erc-format-timestamp ct erc-timestamp-format)))
@@ -270,7 +270,7 @@ or `erc-send-modify-hook'."
                           ;; be different on different entries (bug#22700).
                           (list 'cursor-sensor-functions
                                  ;; Regions are no longer contiguous ^
-                                 '(erc--echo-ts-csf) 'erc-ts ct))))))
+                                 '(erc--echo-ts-csf) 'erc--ts ct))))))
 
 (defvar-local erc-timestamp-last-window-width nil
   "The width of the last window that showed the current buffer.
@@ -403,7 +403,7 @@ non-nil."
                    ;; Skip a line that's just a timestamp.
                    ((> beg (point))))
           (delete-region beg (1+ end)))
-        (when-let (time (erc--get-inserted-msg-prop 'erc-ts))
+        (when-let (time (erc--get-inserted-msg-prop 'erc--ts))
           (insert (format-time-string "[%H:%M:%S] " time)))
         (zerop (forward-line))))
   "")
@@ -660,8 +660,7 @@ truncating `erc-timestamp-format-left' prior to rendering.  
A
 value of t means the option's value doesn't require trimming.")
 
 (defun erc-stamp--propertize-left-date-stamp ()
-  (add-text-properties (point-min) (1- (point-max))
-                       '(field erc-timestamp erc-stamp-type date-left))
+  (add-text-properties (point-min) (1- (point-max)) '(field erc-timestamp))
   (erc--hide-message 'timestamp)
   (run-hooks 'erc-stamp--insert-date-hook))
 
@@ -711,8 +710,8 @@ value of t means the option's value doesn't require 
trimming.")
         (setq erc-timestamp-last-inserted-left nil)
         (let* ((aligned (erc-stamp--time-as-day ct))
                (erc-stamp--current-time aligned)
-               ;; Forget current `erc-cmd', etc.
-               (erc--msg-props (map-into `((erc-msg . datestamp))
+               ;; Forget current `erc--cmd', etc.
+               (erc--msg-props (map-into `((erc--msg . datestamp))
                                          'hash-table))
                (erc-timestamp-last-inserted-left rendered)
                erc-timestamp-format erc-away-timestamp-format)
@@ -867,7 +866,7 @@ Return the empty string if FORMAT is nil."
             erc-stamp--csf-props-updated-p nil)
           (unless erc-stamp--csf-props-updated-p
             (setq erc-stamp--csf-props-updated-p t)
-            (let ((erc--msg-props (map-into '((erc-ts . t)) 'hash-table)))
+            (let ((erc--msg-props (map-into '((erc--ts . t)) 'hash-table)))
               (with-silent-modifications
                 (erc--traverse-inserted
                  (point-min) erc-insert-marker
@@ -889,7 +888,7 @@ Return the empty string if FORMAT is nil."
 
 (defun erc-stamp--add-csf-on-post-modify ()
   "Add `cursor-sensor-functions' to narrowed buffer."
-  (when (erc--check-msg-prop 'erc-ts)
+  (when (erc--check-msg-prop 'erc--ts)
     (put-text-property (point-min) (1- (point-max))
                        'cursor-sensor-functions '(erc--echo-ts-csf))))
 
@@ -940,7 +939,7 @@ enabled when the message was inserted."
 (defun erc-stamp--on-clear-message (&rest _)
   "Return `dont-clear-message' when operating inside the same stamp."
   (and erc-stamp--last-stamp erc-echo-timestamps
-       (eq (erc--get-inserted-msg-prop 'erc-ts) erc-stamp--last-stamp)
+       (eq (erc--get-inserted-msg-prop 'erc--ts) erc-stamp--last-stamp)
        'dont-clear-message))
 
 (defun erc-echo-timestamp (dir stamp &optional zone)
@@ -950,7 +949,7 @@ hours (or seconds, if its abs value is larger than 14), and
 interpret a \"raw\" prefix as UTC.  To specify a zone for use
 with the option `erc-echo-timestamps', see the companion option
 `erc-echo-timestamp-zone'."
-  (interactive (list nil (erc--get-inserted-msg-prop 'erc-ts)
+  (interactive (list nil (erc--get-inserted-msg-prop 'erc--ts)
                      (pcase current-prefix-arg
                        ((and (pred numberp) v)
                         (if (<= (abs v) 14) (* v 3600) v))
@@ -964,7 +963,7 @@ with the option `erc-echo-timestamps', see the companion 
option
       (setq erc-stamp--last-stamp nil))))
 
 (defun erc--echo-ts-csf (_window _before dir)
-  (erc-echo-timestamp dir (erc--get-inserted-msg-prop 'erc-ts)))
+  (erc-echo-timestamp dir (erc--get-inserted-msg-prop 'erc--ts)))
 
 (defun erc-stamp--update-saved-position (&rest _)
   (remove-hook 'erc-stamp--insert-date-hook
diff --git a/lisp/erc/erc-status-sidebar.el b/lisp/erc/erc-status-sidebar.el
index d2ecce94bcd..98d5a321385 100644
--- a/lisp/erc/erc-status-sidebar.el
+++ b/lisp/erc/erc-status-sidebar.el
@@ -130,7 +130,7 @@ buffers, using the functions
   `erc-status-sidebar-pad-hierarchy'
 
 for the above-mentioned purposes.  ERC also accepts a list of
-functions to preform these roles a la carte.  Since the members
+functions to perform these roles a la carte.  Since the members
 of the above sets aren't really interoperable, we don't offer
 them here as customization choices, but you can still specify
 them manually.  See doc strings for a description of their
diff --git a/lisp/erc/erc-track.el b/lisp/erc/erc-track.el
index a36b781e04d..27f20d5c503 100644
--- a/lisp/erc/erc-track.el
+++ b/lisp/erc/erc-track.el
@@ -161,23 +161,39 @@ The faces used are the same as used for text in the 
buffers.
 \(e.g. `erc-pal-face' is used if a pal sent a message to that channel.)"
   :type 'boolean)
 
+(defun erc-track--massage-nick-button-faces (sym val &optional set-fn)
+  "Transform VAL of face-list option SYM to have new defaults.
+Use `set'-compatible SET-FN when given.  If an update was
+performed, set the symbol property `erc-track--obsolete-faces' of
+SYM to t."
+  (let* ((changedp nil)
+         (new (mapcar
+               (lambda (f)
+                 (if (and (eq (car-safe f) 'erc-nick-default-face)
+                          (equal f '(erc-nick-default-face erc-default-face)))
+                     (progn
+                       (setq changedp t)
+                       (put sym 'erc-track--obsolete-faces t)
+                       (cons 'erc-button-nick-default-face (cdr f)))
+                   f))
+               val)))
+    (if set-fn
+        (funcall set-fn sym (if changedp new val))
+      (set-default sym (if changedp new val)))))
+
 (defcustom erc-track-faces-priority-list
   '(erc-error-face
-    (erc-nick-default-face erc-current-nick-face)
     erc-current-nick-face
     erc-keyword-face
-    (erc-nick-default-face erc-pal-face)
     erc-pal-face
     erc-nick-msg-face
     erc-direct-msg-face
     (erc-button erc-default-face)
-    (erc-nick-default-face erc-dangerous-host-face)
     erc-dangerous-host-face
     erc-nick-default-face
-    (erc-nick-default-face erc-default-face)
+    (erc-button-nick-default-face erc-default-face)
     erc-default-face
     erc-action-face
-    (erc-nick-default-face erc-fool-face)
     erc-fool-face
     erc-notice-face
     erc-input-face
@@ -188,6 +204,8 @@ be highlighted using that face.  The first matching face is 
used.
 
 Note that ERC prioritizes certain faces reserved for critical
 messages regardless of this option's value."
+  :package-version '(ERC . "5.6")
+  :set #'erc-track--massage-nick-button-faces
   :type (erc--with-dependent-type-match
          (repeat (choice face (repeat :tag "Combination" face)))
          erc-button))
@@ -209,10 +227,9 @@ setting this variable might not be very useful."
 
 (defcustom erc-track-faces-normal-list
   '((erc-button erc-default-face)
-    (erc-nick-default-face erc-dangerous-host-face)
     erc-dangerous-host-face
     erc-nick-default-face
-    (erc-nick-default-face erc-default-face)
+    (erc-button-nick-default-face erc-default-face)
     erc-default-face
     erc-action-face)
   "A list of faces considered to be part of normal conversations.
@@ -224,9 +241,26 @@ the buffer name will be highlighted using the face from the
 message.  This gives a rough indication that active conversations
 are occurring in these channels.
 
+Note that ERC makes a copy of this option when initializing the
+module.  To see your changes reflected mid-session, cycle
+\\[erc-track-mode].
+
 The effect may be disabled by setting this variable to nil."
-  :type '(repeat (choice face
-                        (repeat :tag "Combination" face))))
+  :package-version '(ERC . "5.6")
+  :set #'erc-track--massage-nick-button-faces
+  :type (erc--with-dependent-type-match
+         (repeat (choice face (repeat :tag "Combination" face)))
+         erc-button))
+
+(defvar erc-track-ignore-normal-contenders-p nil
+  "Compatibility flag to promote only exclusively new \"normal\" faces.
+When non-nil, revert to pre-5.6 behavior in which only a current
+mode-line face that both outranks and is absent from the current
+message is eligible for replacement by a fellow face from
+`erc-track-faces-normal-list' that does appear in the message.
+By extension, when enabled, never replace the current, reigning
+mode-line face if it's present in the current message.  May be
+incompatible with modules introduced after ERC 5.5.")
 
 (defcustom erc-track-position-in-mode-line 'before-modes
   "Where to show modified channel information in the mode-line.
@@ -344,6 +378,37 @@ See `erc-track-position-in-mode-line' for possible values."
 
 ;;; Shortening of names
 
+(defvar erc-track--shortened-names nil
+  "A cons of the last novel name-shortening params and the result.
+The CAR is a hash of environmental inputs such as options and
+parameters passed to `erc-track-shorten-function'.  Its effect is
+only really noticeable during batch processing.")
+
+(defvar erc-track--shortened-names-current-hash nil)
+
+(defun erc-track--shortened-names-set (_ shortened)
+  "Remember SHORTENED names with hash of contextual params."
+  (cl-assert erc-track--shortened-names-current-hash)
+  (setq erc-track--shortened-names
+        (cons erc-track--shortened-names-current-hash shortened)))
+
+(defun erc-track--shortened-names-get (channel-names)
+  "Cache CHANNEL-NAMES with various contextual parameters.
+For now, omit relevant options like `erc-track-shorten-start' and
+friends, even though they do affect the outcome, because they
+likely change too infrequently to matter over sub-second
+intervals and are unlikely to be let-bound or set locally."
+  (when-let ((hash (setq erc-track--shortened-names-current-hash
+                         (sxhash-equal (list channel-names
+                                             (buffer-list)
+                                             erc-track-shorten-function))))
+             (erc-track--shortened-names)
+             ((= hash (car erc-track--shortened-names))))
+    (cdr erc-track--shortened-names)))
+
+(gv-define-simple-setter erc-track--shortened-names-get
+                         erc-track--shortened-names-set)
+
 (defun erc-track-shorten-names (channel-names)
   "Call `erc-unique-channel-names' with the correct parameters.
 This function is a good value for `erc-track-shorten-function'.
@@ -518,6 +583,9 @@ keybindings will not do anything useful."
         (progn
           (add-hook 'window-configuration-change-hook #'erc-user-is-active)
           (add-hook 'erc-send-completed-hook #'erc-user-is-active)
+           ;; FIXME find out why this uses `erc-server-001-functions'.
+           ;; `erc-user-is-active' runs when `erc-server-connected' is
+           ;; non-nil.  But this hook usually only runs when it's nil.
           (add-hook 'erc-server-001-functions #'erc-user-is-active))
        (erc-track-add-to-mode-line erc-track-position-in-mode-line)
        (erc-update-mode-line)
@@ -528,6 +596,8 @@ keybindings will not do anything useful."
      ;; enable the tracking keybindings
      (add-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe)
      (erc-track-minor-mode-maybe))
+   (add-hook 'erc-mode-hook #'erc-track--setup)
+   (unless erc--updating-modules-p (erc-buffer-do #'erc-track--setup))
    (add-hook 'erc-networks--copy-server-buffer-functions
              #'erc-track--replace-killed-buffer))
   ;; Disable:
@@ -539,6 +609,7 @@ keybindings will not do anything useful."
                        #'erc-user-is-active)
           (remove-hook 'erc-send-completed-hook #'erc-user-is-active)
           (remove-hook 'erc-server-001-functions #'erc-user-is-active)
+           ;; FIXME remove this if unused.
           (remove-hook 'erc-timer-hook #'erc-user-is-active))
        (remove-hook 'window-configuration-change-hook
                    #'erc-window-configuration-change)
@@ -548,9 +619,12 @@ keybindings will not do anything useful."
      (remove-hook 'erc-connect-pre-hook #'erc-track-minor-mode-maybe)
      (when erc-track-minor-mode
        (erc-track-minor-mode -1)))
+   (remove-hook 'erc-mode-hook #'erc-track--setup)
+   (erc-buffer-do #'erc-track--setup)
    (remove-hook 'erc-networks--copy-server-buffer-functions
                 #'erc-track--replace-killed-buffer)))
 
+;; FIXME move this above the module definition.
 (defcustom erc-track-when-inactive nil
   "Enable channel tracking even for visible buffers, if you are inactive."
   :type 'boolean
@@ -562,6 +636,51 @@ keybindings will not do anything useful."
               (erc-track-enable))
           (set sym val))))
 
+(defvar-local erc-track--normal-faces nil
+  "Local copy of `erc-track-faces-normal-list' as a hash table.")
+
+(defun erc-track--setup ()
+  "Initialize a buffer for use with the `track' module.
+If this is a server buffer or `erc-track-faces-normal-list' is
+locally bound, create a new `erc-track--normal-faces' for the
+current buffer.  Otherwise, set the local value to the server
+buffer's."
+  (if erc-track-mode
+      (let ((existing (erc-with-server-buffer erc-track--normal-faces))
+            (localp (and erc--target
+                         (local-variable-p 'erc-track-faces-normal-list)))
+            (opts '(erc-track-faces-normal-list erc-track-faces-priority-list))
+            warnp table)
+        ;; Don't bother warning users who've disabled `button'.
+        (unless (or erc--target (not (or (bound-and-true-p erc-button-mode)
+                                         (memq 'button erc-modules))))
+          (when (or localp (local-variable-p 'erc-track-faces-priority-list))
+            (dolist (opt opts)
+              (erc-track--massage-nick-button-faces opt (symbol-value opt)
+                                                    #'set)))
+          (dolist (opt opts)
+            (when (get opt 'erc-track--obsolete-faces)
+              (push opt warnp)
+              (put opt 'erc-track--obsolete-faces nil)))
+          (when warnp
+            (erc--warn-once-before-connect 'erc-track-mode
+              (if (cdr warnp) "Options " "Option ")
+              (mapconcat (lambda (o) (format "`%S'" o)) warnp " and ")
+              (if (cdr warnp) " contain" " contains")
+              " an obsolete item, %S, intended to match buttonized nicknames."
+              " ERC has changed it to %S for the current session."
+              " Please save the current value to silence this message."
+              '(erc-nick-default-face erc-default-face)
+              '(erc-button-nick-default-face erc-default-face))))
+        (when (or (null existing) localp)
+          (setq table (map-into (mapcar (lambda (f) (cons f f))
+                                        erc-track-faces-normal-list)
+                                '(hash-table :test equal :weakness value))))
+        (setq erc-track--normal-faces (or table existing))
+        (unless (or localp existing)
+          (erc-with-server-buffer (setq erc-track--normal-faces table))))
+    (kill-local-variable 'erc-track--normal-faces)))
+
 ;;; Visibility
 
 (defvar erc-buffer-activity nil
@@ -705,10 +824,13 @@ Use `erc-make-mode-line-buffer-name' to create buttons."
                                            (or (buffer-name buf)
                                                ""))
                                         buffers))
-                    (short-names (if (functionp erc-track-shorten-function)
-                                     (funcall erc-track-shorten-function
-                                              long-names)
-                                   long-names))
+                     (erc-track--shortened-names-current-hash nil)
+                     (short-names
+                      (if (functionp erc-track-shorten-function)
+                          (with-memoization
+                              (erc-track--shortened-names-get long-names)
+                            (funcall erc-track-shorten-function long-names))
+                        long-names))
                     strings)
                (while buffers
                  (when (car short-names)
@@ -766,7 +888,12 @@ instead.  This has the effect of allowing the current mode 
line
 face, if a member of `erc-track-faces-normal-list', to be
 replaced with another with lower priority face from NEW-FACES, if
 that face with highest priority in NEW-FACES is also a member of
-`erc-track-faces-normal-list'."
+`erc-track-faces-normal-list'.
+
+To put it another way, when CUR-FACE outranks all NEW-FACES and
+doesn't appear among them, it's eligible to be replaced with a
+fellow \"normal\" from NEW-FACES.  But if it does appear among
+them, it can't be replaced."
   (let ((choice (catch 'face
                   (dolist (candidate erc-track-faces-priority-list)
                     (when (or (equal candidate cur-face)
@@ -785,8 +912,55 @@ that face with highest priority in NEW-FACES is also a 
member of
               choice))
         choice))))
 
+(defvar erc-track--alt-normals-function nil
+  "A function to possibly elect a \"normal\" face.
+Called with the current incumbent and the worthiest new contender
+followed by all new contending faces and so-called \"normal\"
+faces.  See `erc-track--select-mode-line-face' for their meanings
+and expected types.  This function should return a face or nil.")
+
+(defun erc-track--select-mode-line-face (cur-face new-faces ranks normals)
+  "Return CUR-FACE or a replacement for displaying in the mode-line, or nil.
+Expect RANKS to be a list of faces and both NORMALS and the car
+of NEW-FACES to be hash tables mapping faces to non-nil values.
+Assume the latter's makeup and that of RANKS to resemble
+`erc-track-face-normal-list' and `erc-track-faces-priority-list'.
+If NEW-FACES has a cdr, expect it to be its car's contents
+ordered from most recently seen (later in the buffer) to
+earliest.  In general, act like `erc-track-select-mode-line-face'
+except appeal to `erc-track--alt-normals-function' if it's
+non-nil, falling back on reconsidering NEW-FACES when CUR-FACE
+outranks all its members.  That is, choose the first among RANKS
+in NEW-FACES not equal to CUR-FACE.  Failing that, choose the
+first face in NEW-FACES that's also in NORMALS, assuming
+NEW-FACES has a cdr."
+  (cl-check-type erc-track-ignore-normal-contenders-p null)
+  (cl-check-type new-faces cons)
+  (when-let ((choice (catch 'face
+                       (dolist (candidate ranks)
+                         (when (or (equal candidate cur-face)
+                                   (gethash candidate (car new-faces)))
+                           (throw 'face candidate))))))
+    (or (and erc-track--alt-normals-function
+             (funcall erc-track--alt-normals-function
+                      cur-face choice new-faces normals))
+        (and (equal choice cur-face)
+             (gethash choice normals)
+             (catch 'face
+               (progn
+                 (dolist (candidate ranks)
+                   (when (and (not (equal candidate choice))
+                              (gethash candidate (car new-faces))
+                              (gethash choice normals))
+                     (throw 'face candidate)))
+                 (dolist (candidate (cdr new-faces))
+                   (when (and (not (equal candidate choice))
+                              (gethash candidate normals))
+                     (throw 'face candidate))))))
+        choice)))
+
 (defvar erc-track--skipped-msgs '(datestamp)
-  "Values of `erc-msg' text prop to ignore.")
+  "Values of `erc--msg' text prop to ignore.")
 
 (defun erc-track-modified-channels ()
   "Hook function for `erc-insert-post-hook'.
@@ -806,7 +980,7 @@ the current buffer is in `erc-mode'."
                                                  erc-track-exclude-types)
                         ;; Skip certain non-server-sent messages.
                         (and (not parsed)
-                             (erc--check-msg-prop 'erc-msg
+                             (erc--check-msg-prop 'erc--msg
                                                   erc-track--skipped-msgs))))))
        ;; If the active buffer is not visible (not shown in a
        ;; window), and not to be excluded, determine the kinds of
@@ -819,31 +993,43 @@ the current buffer is in `erc-mode'."
        ;; (in the car), change its face attribute (in the cddr) if
        ;; necessary.  See `erc-modified-channels-alist' for the
        ;; exact data structure used.
-        (let ((faces (erc-faces-in (buffer-string)))
-              (erc-track-faces-priority-list
-               `(,@erc-track--attn-faces ,@erc-track-faces-priority-list)))
-         (unless (and
-                  (or (eq erc-track-priority-faces-only 'all)
-                      (member this-channel erc-track-priority-faces-only))
-                  (not (catch 'found
-                         (dolist (f faces)
-                           (when (member f erc-track-faces-priority-list)
-                             (throw 'found t))))))
+        (when-let
+            ((faces (if erc-track-ignore-normal-contenders-p
+                        (erc-faces-in (buffer-string))
+                      (erc-track--get-faces-in-current-message)))
+             (normals erc-track--normal-faces)
+             (erc-track-faces-priority-list
+              `(,@erc-track--attn-faces ,@erc-track-faces-priority-list))
+             (ranks erc-track-faces-priority-list)
+             ((not (and
+                    (or (eq erc-track-priority-faces-only 'all)
+                        (member this-channel erc-track-priority-faces-only))
+                    (not (catch 'found
+                           (dolist (f ranks)
+                             (when (gethash f (or (car-safe faces) faces))
+                               (throw 'found t)))))))))
+          (progn ; FIXME remove `progn' on next major edit
            (if (not (assq (current-buffer) erc-modified-channels-alist))
                ;; Add buffer, faces and counts
                (setq erc-modified-channels-alist
                      (cons (cons (current-buffer)
                                  (cons
-                                   1 (erc-track-select-mode-line-face
-                                      nil faces)))
+                                   1 (if erc-track-ignore-normal-contenders-p
+                                         (erc-track-select-mode-line-face
+                                          nil faces)
+                                       (erc-track--select-mode-line-face
+                                        nil faces ranks normals))))
                            erc-modified-channels-alist))
              ;; Else modify the face for the buffer, if necessary.
              (when faces
                (let* ((cell (assq (current-buffer)
                                   erc-modified-channels-alist))
                       (old-face (cddr cell))
-                      (new-face (erc-track-select-mode-line-face
-                                  old-face faces)))
+                       (new-face (if erc-track-ignore-normal-contenders-p
+                                     (erc-track-select-mode-line-face
+                                      old-face faces)
+                                   (erc-track--select-mode-line-face
+                                    old-face faces ranks normals))))
                  (setcdr cell (cons (1+ (cadr cell)) new-face)))))
            ;; And display it
            (erc-modified-channels-display)))
@@ -872,6 +1058,30 @@ the current buffer is in `erc-mode'."
           (push cur faces)))
     faces))
 
+(defvar erc-track--face-reject-function nil
+  "Function called with face in current buffer to massage or reject.")
+
+(defun erc-track--get-faces-in-current-message ()
+  "Collect all faces in the narrowed buffer.
+Return a cons of a hash table and a list ordered from most
+recently seen to earliest seen."
+  (let ((i (text-property-not-all (point-min) (point-max) 'font-lock-face nil))
+        (seen (make-hash-table :test #'equal))
+        ;;
+        (rfaces ())
+        (faces (make-hash-table :test #'equal)))
+    (while-let ((i)
+                (cur (get-text-property i 'face)))
+      (unless (gethash cur seen)
+        (puthash cur t seen)
+        (when erc-track--face-reject-function
+          (setq cur (funcall erc-track--face-reject-function cur)))
+        (when cur
+          (push cur rfaces)
+          (puthash cur t faces)))
+      (setq i (next-single-property-change i 'font-lock-face)))
+    (cons faces rfaces)))
+
 ;;; Buffer switching
 
 (defvar erc-track-last-non-erc-buffer nil
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 616129bf780..faa2cbefd1b 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -154,26 +154,27 @@ visiting and editing inserted messages.  Modules should 
align
 their markers accordingly.  The following properties have meaning
 as of ERC 5.6:
 
- - `erc-msg': a symbol, guaranteed present; values include:
-   `msg', signifying a `PRIVMSG' or an incoming `NOTICE';
-   `unknown', a fallback for `erc-display-message'; a catalog
-    key, such as `s401' or `finished'; an `erc-display-message'
-    TYPE parameter, like `notice'
+ - `erc--msg': a symbol, guaranteed present; possible values
+    include `unknown', a fallback used by `erc-display-message'; a
+    catalog key, such as `s401' or `finished'; an
+   `erc-display-message' TYPE parameter, like `notice'
 
- - `erc-cmd': a message's associated IRC command, as read by
+ - `erc--cmd': a message's associated IRC command, as read by
    `erc--get-eq-comparable-cmd'; currently either a symbol, like
    `PRIVMSG', or a number, like 5, which represents the numeric
     \"005\"; absent on \"local\" messages, such as simple warnings
     and help text, and on outgoing messages unless echoed back by
     the server (assuming future support)
 
- - `erc-ctcp': a CTCP command, like `ACTION'
+ - `erc--spkr': a string, the nick of the person speaking
 
- - `erc-ts': a timestamp, possibly provided by the server; as of
+ - `erc--ctcp': a CTCP command, like `ACTION'
+
+ - `erc--ts': a timestamp, possibly provided by the server; as of
     5.6, a ticks/hertz pair on Emacs 29 and above, and a \"list\"
     type otherwise; managed by the `stamp' module
 
- - `erc-ephemeral': a symbol prefixed by or matching a module
+ - `erc--ephemeral': a symbol prefixed by or matching a module
     name; indicates to other modules and members of modification
     hooks that the current message should not affect stateful
     operations, such as recording a channel's most recent speaker
@@ -191,10 +192,6 @@ front shadow any that follow.  Ignored when 
`erc--msg-props' is
 already non-nil.")
 
 ;; Forward declarations
-(defvar tabbar--local-hlf)
-(defvar motif-version-string)
-(defvar gtk-version-string)
-
 (declare-function decoded-time-period "time-date" (time))
 (declare-function iso8601-parse-duration "iso8601" (string))
 (declare-function word-at-point "thingatpt" (&optional no-properties))
@@ -477,13 +474,14 @@ Functions are passed a buffer as the first argument."
   :group 'erc-hooks
   :type 'hook)
 
-
-(defvar-local erc-channel-users nil
+(defvaralias 'erc-channel-users 'erc-channel-members)
+(defvar-local erc-channel-members nil
   "Hash table of members in the current channel.
-It associates nicknames with cons cells of the form:
-\(USER . MEMBER-DATA) where USER is a pointer to an
-erc-server-user struct, and MEMBER-DATA is a pointer to an
-erc-channel-user struct.")
+It associates nicknames with cons cells of the form
+\(SERVER-USER . MEMBER-DATA), where SERVER-USER is a
+`erc-server-user' object and MEMBER-DATA is a `erc-channel-user'
+object.  Convenient abbreviations for these two components are
+`susr' and `cusr', along with `cmem' for the pair.")
 
 (defvar-local erc-server-users nil
   "Hash table of users on the current server.
@@ -600,6 +598,29 @@ Removes all users in the current channel.  This is called 
by
              erc-channel-users)
     (clrhash erc-channel-users)))
 
+(defmacro erc--define-channel-user-status-compat-getter (name n)
+  "Define a gv getter for historical `erc-channel-user' status slot NAME.
+Expect NAME to be a string and N to be its associated power-of-2
+\"enumerated flag\" integer."
+  `(defun ,(intern (concat "erc-channel-user-" name)) (u)
+     ,(format "Get equivalent of pre-5.6 `%s' slot for `erc-channel-user'."
+              name)
+     (declare (gv-setter (lambda (v)
+                           (macroexp-let2 nil v v
+                             (,'\`(let ((val (erc-channel-user-status ,',u)))
+                                    (setf (erc-channel-user-status ,',u)
+                                          (if ,',v
+                                              (logior val ,n)
+                                            (logand val ,(lognot n))))
+                                    ,',v))))))
+     (= ,n (logand ,n (erc-channel-user-status u)))))
+
+(erc--define-channel-user-status-compat-getter "voice"  1)
+(erc--define-channel-user-status-compat-getter "halfop" 2)
+(erc--define-channel-user-status-compat-getter "op"     4)
+(erc--define-channel-user-status-compat-getter "admin"  8)
+(erc--define-channel-user-status-compat-getter "owner" 16)
+
 (defun erc-channel-user-owner-p (nick)
   "Return non-nil if NICK is an owner of the current channel."
   (and nick
@@ -1138,7 +1159,13 @@ user after \"/PART\"."
 ;; Hooks
 
 (defgroup erc-hooks nil
-  "Hook variables for fancy customizations of ERC."
+  "Hooks for ERC.
+Users of the interactive client should be aware that many of
+these hooks have names predating the modern convention of
+conveying abnormality via the \"-function\" suffix.  Users should
+likewise be aware that built-in and third-party modules use these
+hooks as well, and some of their variables may be buffer-local in
+particular sessions and/or `let'-bound for spells."
   :group 'erc)
 
 (defcustom erc-mode-hook nil
@@ -1148,9 +1175,8 @@ user after \"/PART\"."
   :options '(erc-add-scroll-to-bottom))
 
 (defcustom erc-timer-hook nil
-  "Put functions which should get called more or less periodically here.
-The idea is that servers always play ping pong with the client, and so there
-is no need for any idle-timer games with Emacs."
+  "Abnormal hook run after each response handler.
+Called with a float returned from `erc-current-time'."
   :group 'erc-hooks
   :type 'hook)
 
@@ -1194,13 +1220,18 @@ The struct has three slots:
   `string': The current input string.
   `insertp': Whether the string should be inserted into the erc buffer.
   `sendp': Whether the string should be sent to the irc server.
+
+And one \"phony\" slot only accessible by hook members at runtime:
+
   `refoldp': Whether the string should be re-split per protocol limits.
 
 This hook runs after protocol line splitting has taken place, so
 the value of `string' is originally \"pre-filled\".  If you need
-ERC to refill the entire payload before sending it, set the
-`refoldp' slot to a non-nil value.  Preformatted text and encoded
-subprotocols should probably be handled manually."
+ERC to refill the entire payload before sending it, set the phony
+`refoldp' slot to a non-nil value.  Note that this refilling is
+only a convenience, and modules with special needs, such as
+preserving \"preformatted\" text or encoding for subprotocol
+\"tunneling\", should handle splitting manually."
   :group 'erc
   :type 'hook
   :version "27.1")
@@ -1450,9 +1481,8 @@ See also `erc-show-my-nick'."
 
 ;; Debugging support
 
-(defvar erc-log-p nil
-  "When set to t, generate debug messages in a separate debug buffer.")
-
+;; FIXME if this variable plays some role, indicate that here.
+;; Otherwise, deprecate.
 (defvar erc-debug-log-file (expand-file-name "ERC.debug")
   "Debug log file name.")
 
@@ -2189,7 +2219,7 @@ removed from the list will be disabled."
            move-to-prompt)
     (const :tag "netsplit: Detect netsplits" netsplit)
     (const :tag "networks: Provide data about IRC networks" networks)
-    (const :tag "nickbar: Show nicknames in a dyamic side window" nickbar)
+    (const :tag "nickbar: Show nicknames in a dynamic side window" nickbar)
     (const :tag "nicks: Uniquely colorize nicknames in target buffers" nicks)
     (const :tag "noncommands: Deprecated. See module `command-indicator'."
            noncommands)
@@ -3004,23 +3034,40 @@ target, and an `erc-server-send' FORCE flag.")
 ;; Sending and displaying are provided separately to afford modules
 ;; more flexibility, e.g., to forgo displaying on the way out when
 ;; expecting the server to echo messages back and/or to associate
-;; outgoing messages with IDs generated for `erc-ephemeral'
+;; outgoing messages with IDs generated for `erc--ephemeral'
 ;; placeholders.
 (defun erc--send-action-perform-ctcp (target string force)
   "Send STRING to TARGET, possibly immediately, with FORCE."
   (erc-send-ctcp-message target (format "ACTION %s" string) force))
 
+(defvar erc--use-language-catalog-for-ctcp-action-p nil
+  "When non-nil, use `ACTION' entry from language catalog for /ME's.
+Otherwise, use `ctcp-action' or `ctcp-action-input' from the
+internal `-speaker' catalog.  This is an escape hatch to restore
+pre-5.6 behavior for the `font-lock-face' property of incoming
+and outgoing \"CTCP ACTION\" messages, whose pre-buttonized state
+was a single interval of `erc-input-face' or `erc-action-face'.
+Newer modules, like `fill-wrap' and `nicks', are incompatible with
+this format style.  If you use this, please ask ERC to expose it
+as a public variable via \\[erc-bug] or similar.")
+
 (defun erc--send-action-display (string)
-  "Display STRING as an outgoing \"CTCP ACTION\" message."
+  "Display STRING as an outgoing \"CTCP ACTION\" message.
+Propertize the message according to the compatibility flag
+`erc--use-language-catalog-for-ctcp-action-p'."
   ;; Allow hooks acting on inserted PRIVMSG and NOTICES to process us.
-  (let ((erc--msg-prop-overrides `((erc-msg . msg)
-                                   (erc-ctcp . ACTION)
+  (let ((erc--msg-prop-overrides `((erc--ctcp . ACTION)
                                    ,@erc--msg-prop-overrides))
         (nick (erc-current-nick)))
-    (setq nick (propertize nick 'erc-speaker nick
-                           'font-lock-face 'erc-my-nick-face))
-    (erc-display-message nil '(t action input) (current-buffer)
-                         'ACTION ?n nick ?a string ?u "" ?h "")))
+    (if erc--use-language-catalog-for-ctcp-action-p
+        (progn (erc--ensure-spkr-prop nick)
+               (erc-display-message nil 'input (current-buffer) 'ACTION
+                                    ?n (propertize nick 'erc--speaker nick)
+                                    ?a string ?u "" ?h ""))
+      (let ((erc-current-message-catalog erc--message-speaker-catalog))
+        (erc-display-message nil nil (current-buffer) 'ctcp-action-input
+                             ?p (erc-get-channel-membership-prefix nick)
+                             ?n (erc--speakerize-nick nick) ?m string)))))
 
 (defun erc--send-action (target string force)
   "Display STRING, then send to TARGET as a \"CTCP ACTION\" message."
@@ -3029,6 +3076,21 @@ target, and an `erc-server-send' FORCE flag.")
 
 ;; Display interface
 
+(defun erc--ensure-spkr-prop (nick &optional overrides)
+  "Add NICK as `erc--spkr' to the current \"msg props\" environment.
+Prefer `erc--msg-props' over `erc--msg-prop-overrides' when both
+are available.  Also include any members of the alist OVERRIDES,
+when present.  Assume NICK itself to be free of any text props,
+and return it."
+  (cond (erc--msg-props
+         (puthash 'erc--spkr nick erc--msg-props)
+         (dolist (entry overrides)
+           (puthash (car entry) (cdr entry) erc--msg-props)))
+        (erc--msg-prop-overrides
+         (setq erc--msg-prop-overrides
+               `((erc--spkr . ,nick) ,@overrides ,@erc--msg-prop-overrides))))
+  nick)
+
 (defun erc-string-invisible-p (string)
   "Check whether STRING is invisible or not.
 I.e. any char in it has the `invisible' property set."
@@ -3142,20 +3204,20 @@ Return ONLY one side when the first arg is `end' or 
`beg'.  With
 POINT, search from POINT instead of `point'."
   ;; TODO add edebug spec.
   `(let* ((point ,(or point '(point)))
-          (at-start-p (get-text-property point 'erc-msg)))
+          (at-start-p (get-text-property point 'erc--msg)))
      (and-let*
          (,@(and (member only '(nil beg 'beg))
                  '((b (or (and at-start-p point)
                           (and-let*
                               ((p (previous-single-property-change point
-                                                                   'erc-msg)))
+                                                                   'erc--msg)))
                             (if (= p (1- point))
-                                (if (get-text-property p 'erc-msg) p (1- p))
+                                (if (get-text-property p 'erc--msg) p (1- p))
                               (1- p)))))))
           ,@(and (member only '(nil end 'end))
                  '((e (1- (next-single-property-change
                            (if at-start-p (1+ point) point)
-                           'erc-msg nil erc-insert-marker))))))
+                           'erc--msg nil erc-insert-marker))))))
        ,(pcase only
           ('(quote beg) 'b)
           ('(quote end) 'e)
@@ -3184,12 +3246,12 @@ If END is a marker, possibly update its position."
     (set-marker end (min erc-insert-marker end)))
   (save-excursion
     (goto-char beg)
-    (let ((b (if (get-text-property (point) 'erc-msg)
+    (let ((b (if (get-text-property (point) 'erc--msg)
                  (point)
-               (next-single-property-change (point) 'erc-msg nil end))))
+               (next-single-property-change (point) 'erc--msg nil end))))
       (while-let ((b)
                   ((< b end))
-                  (e (next-single-property-change (1+ b) 'erc-msg nil end)))
+                  (e (next-single-property-change (1+ b) 'erc--msg nil end)))
         (save-restriction
           (narrow-to-region b e)
           (funcall fn))
@@ -3267,7 +3329,7 @@ modification hooks)."
                   (let ((props (if erc--msg-props
                                    (erc--order-text-properties-from-hash
                                     erc--msg-props)
-                                 '(erc-msg unknown))))
+                                 '(erc--msg unknown))))
                     (add-text-properties (point-min) (1+ (point-min)) props)))
                 (erc--refresh-prompt)))))
         (run-hooks 'erc-insert-done-hook)
@@ -3340,8 +3402,8 @@ the old pattern (erc-display-line (erc-make-notice) 
my-buffer) as
 being equivalent to a `erc-display-message' TYPE of `notice'."
   (let ((erc--msg-prop-overrides erc--msg-prop-overrides))
     (when (eq 'erc-notice-face (get-text-property 0 'font-lock-face string))
-      (unless (assq 'erc-msg erc--msg-prop-overrides)
-        (push '(erc-msg . notice) erc--msg-prop-overrides)))
+      (unless (assq 'erc--msg erc--msg-prop-overrides)
+        (push '(erc--msg . notice) erc--msg-prop-overrides)))
     (erc-display-message nil nil buffer string)))
 
 (defvar erc--merge-text-properties-p nil
@@ -3351,12 +3413,14 @@ being equivalent to a `erc-display-message' TYPE of 
`notice'."
 ;; values and optionally dispense archetypal constants in their place
 ;; in order to ensure all occurrences of some list (a b) across all
 ;; text-properties in all ERC buffers are actually the same object.
-(defun erc--merge-prop (from to prop val &optional object)
+(defun erc--merge-prop (from to prop val &optional object cache-fn)
   "Combine existing PROP values with VAL between FROM and TO in OBJECT.
 For spans where PROP is non-nil, cons VAL onto the existing
 value, ensuring a proper list.  Otherwise, just set PROP to VAL.
 When VAL is itself a list, prepend its members onto an existing
-value.  See also `erc-button-add-face'."
+value.  Call CACHE-FN, when given, with the new value for prop.
+It must return a suitable replacement or the same value.  See
+also `erc-button-add-face'."
   (let ((old (get-text-property from prop object))
         (pos from)
         (end (next-single-property-change from prop object to))
@@ -3370,6 +3434,8 @@ value.  See also `erc-button-add-face'."
                           (append val (ensure-list old))
                         (cons val (ensure-list old))))
                   val))
+      (when cache-fn
+        (setq new (funcall cache-fn new)))
       (put-text-property pos end prop new object)
       (setq pos end
             old (get-text-property pos prop object)
@@ -3458,7 +3524,8 @@ subsequent message."
              (substring (delete-and-extract-region (1- (point)) (1+ end))
                         -1))))))))
 
-(defvar erc--ranked-properties '(erc-msg erc-ts erc-cmd))
+(defvar erc--ranked-properties
+  '(erc--msg erc--spkr erc--ts erc--cmd erc--ctcp erc--ephemeral))
 
 (defun erc--order-text-properties-from-hash (table)
   "Return a plist of text props from items in TABLE.
@@ -3724,32 +3791,29 @@ ERC to process arbitrary informative messages as if 
they'd been
 sent from a server.  That is, guarantee \"local\" messages, for
 which PARSED is typically nil, will be subject to buttonizing,
 filling, and other effects."
-  (let ((string (if (symbolp msg)
-                    (apply #'erc-format-message msg args)
-                  msg))
-        (erc--msg-props
-         (or erc--msg-props
-             (let ((table (make-hash-table :size 5))
-                   (cmd (and parsed (erc--get-eq-comparable-cmd
-                                     (erc-response.command parsed)))))
-               (puthash 'erc-msg
-                        (cond ((and msg (symbolp msg)) msg)
-                              ((and cmd (memq cmd '(PRIVMSG NOTICE)) 'msg))
-                              (type (pcase type
-                                      ((pred symbolp) type)
-                                      ((pred listp)
-                                       (intern (mapconcat #'prin1-to-string
-                                                          type "-")))
-                                      (_ 'unknown)))
-                              (t 'unknown))
-                        table)
-               (when cmd
-                 (puthash 'erc-cmd cmd table))
-               (and-let* ((ovs erc--msg-prop-overrides))
-                 (pcase-dolist (`(,k . ,v) (reverse ovs))
-                   (puthash k v table)))
-               table)))
-        (erc-message-parsed parsed))
+  (let* ((erc--msg-props
+          (or erc--msg-props
+              (let ((table (make-hash-table))
+                    (cmd (and parsed (erc--get-eq-comparable-cmd
+                                      (erc-response.command parsed)))))
+                (puthash 'erc--msg
+                         (cond ((and msg (symbolp msg)) msg)
+                               (type (pcase type
+                                       ((pred symbolp) type)
+                                       ((pred listp)
+                                        (intern (mapconcat #'prin1-to-string
+                                                           type "-")))
+                                       (_ 'unknown)))
+                               (t 'unknown))
+                         table)
+                (when cmd
+                  (puthash 'erc--cmd cmd table))
+                (when erc--msg-prop-overrides
+                  (pcase-dolist (`(,k . ,v) (reverse erc--msg-prop-overrides))
+                    (when v (puthash k v table))))
+                table)))
+         (erc-message-parsed parsed)
+         (string (if (symbolp msg) (apply #'erc-format-message msg args) msg)))
     (setq string
           (cond
            ((null type)
@@ -4646,11 +4710,25 @@ See also `erc-message' and `erc-display-line'."
     (erc--send-message-external line force)))
 
 (defun erc--send-message-external (line force)
-  (erc-message "PRIVMSG" (concat (erc-default-target) " " line) force)
-  (erc-display-line
-   (concat (erc-format-my-nick) line)
-   (current-buffer))
+  "Send a \"PRIVMSG\" to the default target with optional FORCE.
+Expect caller to bind `erc-default-recipients' if needing to
+specify a status-prefixed target."
+  ;; Almost like an echoed message, but without the `erc--cmd'.
+  (let* ((erc-current-message-catalog erc--message-speaker-catalog)
+         (target (erc-default-target))
+         (erc--msg-prop-overrides `((erc--tmp) ,@erc--msg-prop-overrides))
+         ;; This util sets the `erc--spkr' property in ^.
+         (trimmed (erc--statusmsg-target target))
+         (stmsgindc (and trimmed (substring target 0 1)))
+         (queryp (and erc--target (not (erc--target-channel-p erc--target))))
+         (args (erc--determine-speaker-message-format-args
+                (erc-current-nick) line queryp 'privmsgp 'inputp
+                stmsgindc 'prefix)))
+    (erc-message "PRIVMSG" (concat target " " line) force)
+    (push (cons 'erc--msg (car args)) erc--msg-prop-overrides)
+    (apply #'erc-display-message nil nil (current-buffer) args))
   ;; FIXME - treat multiline, run hooks, or remove me?
+  ;; FIXME explain this ^ in more detail or remove.
   t)
 
 (defun erc--send-message-nested (input-line force)
@@ -4969,9 +5047,11 @@ connection or, with -A, all applicable connections.
                             system-configuration
                             (concat
                              (cond ((featurep 'motif)
+                                    (defvar motif-version-string)
                                     (concat ", " (substring
                                                   motif-version-string 4)))
                                    ((featurep 'gtk)
+                                    (defvar gtk-version-string)
                                     (concat ", GTK+ Version "
                                             gtk-version-string))
                                    ((featurep 'x-toolkit) ", X toolkit")
@@ -5256,12 +5336,13 @@ Eventually add a # in front of it, if that turns it 
into a valid channel name."
     (concat "#" channel)))
 
 (defvar erc--own-property-names
-  '( tags erc-speaker erc-parsed display ; core
+  `( tags erc--speaker erc-parsed display ; core
+     ;; `erc--msg-props'
+     ,@erc--ranked-properties
      ;; `erc-display-prompt'
      rear-nonsticky erc-prompt field front-sticky read-only
      ;; stamp
      cursor-intangible cursor-sensor-functions isearch-open-invisible
-     erc-stamp-type
      ;; match
      invisible intangible
      ;; button
@@ -5605,7 +5686,9 @@ manner implied above, which was lost sometime before ERC 
5.4."
   :package-version '(ERC . "5.6") ; revived
   :group 'erc-buffers
   :group 'erc-query
-  :type 'boolean)
+  :type '(choice boolean
+                 (choice :tag "Create pseudo queries for STATUSMSGs"
+                         status)))
 
 (defcustom erc-format-query-as-channel-p t
   "If non-nil, format text from others in a query buffer like in a channel.
@@ -5740,12 +5823,12 @@ and as second argument the event parsed as a vector."
        (not (string-match "^\C-aACTION.*\C-a$" message))))
 
 (defun erc--get-speaker-bounds ()
-  "Return the bounds of `erc-speaker' text property when present.
+  "Return the bounds of `erc--speaker' text property when present.
 Assume buffer is narrowed to the confines of an inserted message."
-  (and-let* (((erc--check-msg-prop 'erc-msg 'msg))
+  (and-let* (((erc--check-msg-prop 'erc--spkr))
              (beg (text-property-not-all (point-min) (point-max)
-                                         'erc-speaker nil)))
-    (cons beg (next-single-property-change beg 'erc-speaker))))
+                                         'erc--speaker nil)))
+    (cons beg (next-single-property-change beg 'erc--speaker))))
 
 (defvar erc--cmem-from-nick-function #'erc--cmem-get-existing
   "Function maybe returning a \"channel member\" cons from a nick.
@@ -5770,53 +5853,263 @@ NUH, and the current `erc-response' object.")
                                                 nick-prefix-face nick))
                          0))
          (msg-face (if privp 'erc-direct-msg-face 'erc-default-face)))
+    (erc--ensure-spkr-prop nick)
     ;; add text properties to text before the nick, the nick and after the nick
     (erc-put-text-property 0 (length mark-s) 'font-lock-face msg-face str)
     (erc-put-text-properties (+ (length mark-s) prefix-len)
                              (+ (length mark-s) (length nick))
-                             '(font-lock-face erc-speaker) str
+                             '(font-lock-face erc--speaker) str
                              (list nick-face
                                    (substring-no-properties nick prefix-len)))
     (erc-put-text-property (+ (length mark-s) (length nick)) (length str)
                            'font-lock-face msg-face str)
     str))
 
-(defcustom erc-format-nick-function 'erc-format-nick
-  "Function to format a nickname for message display."
+;; The format strings in the following `-speaker' catalog shouldn't
+;; contain any non-protocol words, so they make sense in any language.
+
+(defvar erc--message-speaker-statusmsg
+  #("(%p%n%s) %m"
+    0 1 (font-lock-face erc-default-face)
+    1 3 (font-lock-face erc-nick-prefix-face)
+    3 5 (font-lock-face erc-nick-default-face)
+    5 7 (font-lock-face erc-notice-face)
+    7 11 (font-lock-face erc-default-face))
+  "Message template for in-channel status messages.")
+
+(defvar erc--message-speaker-statusmsg-input
+  #("(%p%n%s) %m"
+    0 1 (font-lock-face erc-default-face)
+    1 3 (font-lock-face erc-my-nick-prefix-face)
+    3 5 (font-lock-face erc-my-nick-face)
+    5 7 (font-lock-face erc-notice-face)
+    7 8 (font-lock-face erc-default-face)
+    8 11 (font-lock-face erc-input-face))
+  "Message template for echoed status messages.")
+
+(defvar erc--message-speaker-input-chan-privmsg
+  #("<%p%n> %m"
+    0 1 (font-lock-face erc-default-face)
+    1 3 (font-lock-face erc-my-nick-prefix-face)
+    3 5 (font-lock-face erc-my-nick-face)
+    5 7 (font-lock-face erc-default-face)
+    7 9 (font-lock-face erc-input-face))
+  "Message template for prompt input or echoed PRIVMSG from own nick.")
+
+(defvar erc--message-speaker-input-query-privmsg
+  #("*%n* %m"
+    0 1 (font-lock-face erc-direct-msg-face)
+    1 3 (font-lock-face erc-my-nick-face)
+    3 5 (font-lock-face erc-direct-msg-face)
+    5 7 (font-lock-face erc-input-face))
+  "Message template for prompt input or echoed PRIVMSG query from own nick.")
+
+(defvar erc--message-speaker-input-query-notice
+  #("-%n- %m"
+    0 1 (font-lock-face erc-direct-msg-face)
+    1 3 (font-lock-face erc-my-nick-face)
+    3 5 (font-lock-face erc-direct-msg-face)
+    5 7 (font-lock-face erc-input-face))
+  "Message template for echoed or spoofed query NOTICE from own nick.")
+
+(defvar erc--message-speaker-input-chan-notice
+  #("-%p%n- %m"
+    0 1 (font-lock-face erc-default-face)
+    1 3 (font-lock-face erc-my-nick-prefix-face)
+    3 5 (font-lock-face erc-my-nick-face)
+    5 7 (font-lock-face erc-default-face)
+    7 9 (font-lock-face erc-input-face))
+  "Message template for prompt input or echoed NOTICE from own nick.")
+
+(defvar erc--message-speaker-chan-privmsg
+  #("<%p%n> %m"
+    0 1 (font-lock-face erc-default-face)
+    1 3 (font-lock-face erc-nick-prefix-face)
+    3 5 (font-lock-face erc-nick-default-face)
+    5 9 (font-lock-face erc-default-face))
+  "Message template for a PRIVMSG in a channel.")
+
+(defvar erc--message-speaker-query-privmsg
+  #("*%n* %m"
+    0 1 (font-lock-face erc-direct-msg-face)
+    1 3 (font-lock-face erc-nick-msg-face)
+    3 7 (font-lock-face erc-direct-msg-face))
+  "Message template for a PRIVMSG in query buffer.")
+
+(defvar erc--message-speaker-chan-notice
+  #("-%p%n- %m"
+    0 1 (font-lock-face erc-default-face)
+    1 3 (font-lock-face erc-nick-prefix-face)
+    3 5 (font-lock-face erc-nick-default-face)
+    5 9 (font-lock-face erc-default-face))
+  "Message template for a NOTICE in a channel.")
+
+(defvar erc--message-speaker-query-notice
+  #("-%n- %m"
+    0 1 (font-lock-face erc-direct-msg-face)
+    1 3 (font-lock-face erc-nick-msg-face)
+    3 7 (font-lock-face erc-direct-msg-face))
+  "Message template for a NOTICE in a query buffer.")
+
+(defvar erc--message-speaker-ctcp-action
+  #("* %p%n %m"
+    0 2 (font-lock-face erc-action-face)
+    2 4 (font-lock-face (erc-nick-prefix-face erc-action-face))
+    4 9 (font-lock-face erc-action-face))
+  "Message template for a CTCP ACTION from another user.")
+
+(defvar erc--message-speaker-ctcp-action-input
+  #("* %p%n %m"
+    0 2 (font-lock-face #1=(erc-input-face erc-action-face))
+    2 4 (font-lock-face (erc-my-nick-prefix-face . #1#))
+    4 6 (font-lock-face (erc-my-nick-face . #1#))
+    6 9 (font-lock-face #1#))
+  "Message template for a CTCP ACTION from current client.")
+
+(defvar erc--message-speaker-ctcp-action-statusmsg
+  #("* (%p%n%s) %m"
+    0 3 (font-lock-face erc-action-face)
+    3 5 (font-lock-face (erc-nick-prefix-face erc-action-face))
+    5 7 (font-lock-face erc-action-face)
+    7 9 (font-lock-face (erc-notice-face erc-action-face))
+    9 13 (font-lock-face erc-action-face))
+  "Template for a CTCP ACTION status message from another chan op.")
+
+(defvar erc--message-speaker-ctcp-action-statusmsg-input
+  #("* (%p%n%s) %m"
+    0 3 (font-lock-face #1=(erc-input-face erc-action-face))
+    3 5 (font-lock-face (erc-my-nick-prefix-face . #1#))
+    5 7 (font-lock-face (erc-my-nick-face . #1#))
+    7 9 (font-lock-face (erc-notice-face . #1#))
+    9 13 (font-lock-face #1#))
+  "Template for a CTCP ACTION status message from current client.")
+
+(defun erc--speakerize-nick (nick &optional disp)
+  "Propertize NICK with `erc--speaker' if not already present.
+Do so to DISP instead if it's non-nil.  In either case, assign
+NICK, sans properties, as the `erc--speaker' value.  As a side
+effect, pair the latter string (the same `eq'-able object) with
+the symbol `erc--spkr' in the \"msg prop\" environment for any
+imminent `erc-display-message' invocations.  While doing so,
+include any overrides defined in `erc--message-speaker-catalog'."
+  (let ((plain-nick (substring-no-properties nick)))
+    (erc--ensure-spkr-prop plain-nick (get erc--message-speaker-catalog
+                                           'erc--msg-prop-overrides))
+    (if (text-property-not-all 0 (length (or disp nick))
+                               'erc--speaker nil (or disp nick))
+        (or disp nick)
+      (propertize (or disp nick) 'erc--speaker plain-nick))))
+
+(defun erc--determine-speaker-message-format-args
+    (nick message queryp privmsgp inputp &optional statusmsg prefix disp-nick)
+  "Return a list consisting of a \"speaker\"-template key and spec args.
+Consider the three flags QUERYP, PRIVMSGP, and INPUTP, as well as
+the possibly null STATUSMSG string.  (Combined, these describe
+the context of a newly arrived \"PRIVMSG\" or, when PRIVMSGP is
+nil, a \"NOTICE\").  Interpret QUERYP to mean that MESSAGE is
+directed at the ERC client itself (a direct message), and INPUTP
+to mean MESSAGE is an outgoing or echoed message originating from
+or meant to simulate prompt input.  Interpret a non-nil STATUSMSG
+to mean MESSAGE should be formatted as a special channel message
+intended for privileged members of the same or greater status.
+
+After deciding on the template key for the current \"speaker\"
+catalog, use the remaining arguments, possibly along with
+STATUSMSG, to construct the appropriate spec-args plist forming
+the returned list's tail.  In this plist, pair the char ?n with
+NICK, the nickname of the speaker and ?m with MESSAGE, the
+message body.  When non-nil, assume DISP-NICK to be a possibly
+phony display name to take the place of NICK for ?n.  When PREFIX
+is non-nil, look up NICK's channel-membership status, possibly
+using PREFIX itself if it's an `erc-channel-user' object, which
+it must be when called outside of a channel buffer.  Pair the
+result with the ?p specifier.  When STATUSMSG is non-nil, pair it
+with the ?s specifier.  Ensure unused spec values are the empty
+string rather than nil."
+  (when prefix
+    (setq prefix (erc-get-channel-membership-prefix
+                  (if (erc-channel-user-p prefix) prefix nick))))
+  (when (and queryp erc--target erc-format-query-as-channel-p
+             (not (erc--target-channel-p erc--target)))
+    (setq queryp nil))
+  (list (cond (statusmsg (if inputp 'statusmsg-input 'statusmsg))
+              (privmsgp (if queryp
+                            (if inputp 'input-query-privmsg 'query-privmsg)
+                          (if inputp 'input-chan-privmsg 'chan-privmsg)))
+              (t (if queryp
+                     (if inputp 'input-query-notice 'query-notice)
+                   (if inputp 'input-chan-notice 'chan-notice))))
+        ?p (or prefix "") ?n (erc--speakerize-nick nick disp-nick)
+        ?s (or statusmsg "") ?m message))
+
+(defcustom erc-show-speaker-membership-status nil
+  "Whether to prefix speakers with their channel status.
+For example, when this option is non-nil and some nick \"Alice\"
+has operator status in the current channel, ERC displays their
+leading \"speaker\" label as <@Alice> instead of <Alice>."
+  :package-version '(ERC . "5.6")
+  :group 'erc-display
+  :type 'boolean)
+
+(define-obsolete-variable-alias 'erc-format-nick-function
+  'erc-speaker-from-channel-member-function "30.1")
+(defcustom erc-speaker-from-channel-member-function
+  #'erc-determine-speaker-from-user
+  "Function to determine a message's displayed \"speaker\" label.
+Called with an `erc-server-user' object and an `erc-channel-user'
+object, both possibly nil.  Use this option to do things like
+provide localized display names.  To ask ERC to prepend
+channel-membership \"status\" prefixes, like \"@\", to the
+returned name, see `erc-show-speaker-membership-status'."
+  :package-version '(ERC . "5.6")
   :group 'erc-display
-  :type 'function)
+  :type '(choice (function-item erc-determine-speaker-from-user) function))
 
-(defun erc-format-nick (&optional user _channel-data)
-  "Return the nickname of USER.
-See also `erc-format-nick-function'."
+(define-obsolete-function-alias 'erc-format-nick
+  #'erc-determine-speaker-from-user "30.1")
+(defun erc-determine-speaker-from-user (&optional user _channel-data)
+  "Return nickname slot of `erc-server-user' USER, when non-nil."
   (when user (erc-server-user-nickname user)))
 
-(defun erc-get-user-mode-prefix (user)
+(define-obsolete-function-alias 'erc-get-user-mode-prefix
+  #'erc-get-channel-membership-prefix "30.1")
+(defun erc-get-channel-membership-prefix (user)
+  "Return channel membership prefix for USER as a string.
+Ensure returned string has a `help-echo' text property with the
+corresponding verbose membership type, like \"voice\", as its
+value.  Expect USER to be an `erc-channel-user' object or a
+string nickname, not necessarily downcased."
   (when user
-    (cond ((erc-channel-user-owner-p user)
+    (when (stringp user)
+      (setq user (and erc-channel-users (cdr (erc-get-channel-user user)))))
+    (cond ((null user) "")
+          ((erc-channel-user-owner user)
            (propertize "~" 'help-echo "owner"))
-          ((erc-channel-user-admin-p user)
+          ((erc-channel-user-admin user)
            (propertize "&" 'help-echo "admin"))
-          ((erc-channel-user-op-p user)
+          ((erc-channel-user-op user)
            (propertize "@" 'help-echo "operator"))
-          ((erc-channel-user-halfop-p user)
+          ((erc-channel-user-halfop user)
            (propertize "%" 'help-echo "half-op"))
-          ((erc-channel-user-voice-p user)
+          ((erc-channel-user-voice user)
            (propertize "+" 'help-echo "voice"))
           (t ""))))
 
-(defun erc-format-@nick (&optional user _channel-data)
+(defun erc-format-@nick (&optional user channel-data)
   "Format the nickname of USER showing if USER has a voice, is an
 operator, half-op, admin or owner.  Owners have \"~\", admins have
 \"&\", operators have \"@\" and users with voice have \"+\" as a
-prefix.  Use CHANNEL-DATA to determine op and voice status.  See
-also `erc-format-nick-function'."
+prefix.  Use CHANNEL-DATA to determine op and voice status."
+  (declare (obsolete "see option `erc-show-speaker-membership-status'" "30.1"))
   (when user
     (let ((nick (erc-server-user-nickname user)))
-      (concat (propertize
-               (erc-get-user-mode-prefix nick)
-               'font-lock-face 'erc-nick-prefix-face)
-             nick))))
+      (if (not erc--speaker-status-prefix-wanted-p)
+          (prog1 nick
+            (setq erc--speaker-status-prefix-wanted-p 'erc-format-@nick))
+        (concat (propertize
+                 (erc-get-channel-membership-prefix channel-data)
+                 'font-lock-face 'erc-nick-prefix-face)
+                nick)))))
 
 (defun erc-format-my-nick ()
   "Return the beginning of this user's message, correctly propertized."
@@ -5824,15 +6117,42 @@ also `erc-format-nick-function'."
       (let* ((open "<")
              (close "> ")
              (nick (erc-current-nick))
-             (mode (erc-get-user-mode-prefix nick)))
+             (mode (erc-get-channel-membership-prefix nick)))
+        (erc--ensure-spkr-prop nick)
         (concat
          (propertize open 'font-lock-face 'erc-default-face)
          (propertize mode 'font-lock-face 'erc-my-nick-prefix-face)
-         (propertize nick 'font-lock-face 'erc-my-nick-face 'erc-speaker nick)
+         (propertize nick 'erc--speaker nick 'font-lock-face 'erc-my-nick-face)
          (propertize close 'font-lock-face 'erc-default-face)))
     (let ((prefix "> "))
       (propertize prefix 'font-lock-face 'erc-default-face))))
 
+(defun erc--format-speaker-input-message (message)
+  "Assemble outgoing MESSAGE entered at the prompt for insertion.
+Intend \"input\" to refer to interactive prompt input as well as
+the group of associated message-format templates from the
+\"speaker\" catalog.  Format the speaker portion in a manner
+similar to that performed by `erc-format-my-nick', but use either
+`erc--message-speaker-input-chan-privmsg' or
+`erc--message-speaker-input-query-privmsg' as a formatting
+template, with MESSAGE being the actual message body.  Return a
+copy with possibly shared text-property values."
+  (if-let ((erc-show-my-nick)
+           (nick (erc-current-nick))
+           (pfx (erc-get-channel-membership-prefix nick))
+           (erc-current-message-catalog erc--message-speaker-catalog)
+           (key (if (or erc-format-query-as-channel-p
+                        (erc--target-channel-p erc--target))
+                    'input-chan-privmsg
+                  'input-query-privmsg)))
+      (progn
+        (cond (erc--msg-props (puthash 'erc--msg key erc--msg-props))
+              (erc--msg-prop-overrides (push (cons 'erc--msg key)
+                                             erc--msg-prop-overrides)))
+        (erc-format-message key ?p pfx ?n (erc--speakerize-nick nick)
+                            ?m message))
+    (propertize (concat "> " message) 'font-lock-face 'erc-input-face)))
+
 (defun erc-echo-notice-in-default-buffer (s parsed buffer _sender)
   "Echo a private notice in the default buffer, namely the
 target buffer specified by BUFFER, or there is no target buffer,
@@ -6072,8 +6392,7 @@ See also `erc-display-message'."
         (while queries
           (let* ((type (upcase (car (split-string (car queries)))))
                  (hook (intern-soft (concat "erc-ctcp-query-" type "-hook")))
-                 (erc--msg-prop-overrides `((erc-msg . msg)
-                                            (erc-ctcp . ,(intern type))
+                 (erc--msg-prop-overrides `((erc--ctcp . ,(intern type))
                                             ,@erc--msg-prop-overrides)))
             (if (and hook (boundp hook))
                 (if (string-equal type "ACTION")
@@ -6108,11 +6427,31 @@ See also `erc-display-message'."
     (let ((s (match-string 1 msg))
           (buf (or (erc-get-buffer to proc)
                    (erc-get-buffer nick proc)
-                   (process-buffer proc))))
-      (setq nick (propertize nick 'erc-speaker nick))
-      (erc-display-message
-       parsed 'action buf
-       'ACTION ?n nick ?u login ?h host ?a s))))
+                   (process-buffer proc)))
+          (selfp (erc-current-nick-p nick)))
+      (if erc--use-language-catalog-for-ctcp-action-p
+          (progn
+            (erc--ensure-spkr-prop nick)
+            (setq nick (propertize nick 'erc--speaker nick))
+            (erc-display-message parsed (if selfp 'input 'action) buf
+                                 'ACTION ?n nick ?u login ?h host ?a s))
+        (let* ((obj (and (erc--ctcp-response-p parsed) parsed))
+               (buffer (and obj (erc--ctcp-response-buffer obj)))
+               (stsmsg (and obj (erc--ctcp-response-statusmsg obj)))
+               (prefix (and obj (erc--ctcp-response-prefix obj)))
+               (dispnm (and obj (erc--ctcp-response-dispname obj)))
+               (erc-current-message-catalog erc--message-speaker-catalog))
+          (erc-display-message
+           parsed nil (or buffer buf)
+           (if selfp
+               (if stsmsg 'ctcp-action-statusmsg-input 'ctcp-action-input)
+             (if stsmsg 'ctcp-action-statusmsg 'ctcp-action))
+           ?s (or stsmsg to)
+           ?p (or (and (erc-channel-user-p prefix)
+                       (erc-get-channel-membership-prefix prefix))
+                  "")
+           ?n (erc--speakerize-nick nick dispnm)
+           ?m s))))))
 
 (defvar erc-ctcp-query-CLIENTINFO-hook '(erc-ctcp-query-CLIENTINFO))
 
@@ -6453,6 +6792,19 @@ which USER is a member, and t is returned."
                   (run-hooks 'erc-channel-members-changed-hook))))))
     changed))
 
+;; This exists solely to make `erc-update-current-channel-member' more
+;; readable.  Having to resort to it is admittedly not ideal.  While
+;; it would seem at first glance that we could go further and encode
+;; the combined status in one go, we can't without gating the entire
+;; operation on the parameters `admin', `halfop', etc. being non-nil.
+(defmacro erc--update-cusr-status-if-changed (cuser changed-var status-var)
+  "Maybe update STATUS-VAR slot of `erc-channel-user' CUSER, and CHANGED-VAR."
+  (let ((accessor (intern (format "erc-channel-user-%s" status-var))))
+    `(when (and ,status-var (not (eq (,accessor ,cuser) ,status-var)))
+       (setf (,accessor ,cuser) (and (not (eq ,status-var 'off))
+                                     (and ,status-var t))
+             ,changed-var t))))
+
 (defun erc-update-current-channel-member
   (nick new-nick &optional add voice halfop op admin owner host login 
full-name info
         update-message-time)
@@ -6480,41 +6832,11 @@ See also: `erc-update-user' and 
`erc-update-channel-member'."
     (if cuser
         (progn
           (erc-log (format "update-member: user = %S, cuser = %S" user cuser))
-          (when (and voice
-                     (not (eq (erc-channel-user-voice cuser) voice)))
-            (setq changed t)
-            (setf (erc-channel-user-voice cuser)
-                  (cond ((eq voice 'on) t)
-                        ((eq voice 'off) nil)
-                        (t voice))))
-          (when (and halfop
-                     (not (eq (erc-channel-user-halfop cuser) halfop)))
-            (setq changed t)
-            (setf (erc-channel-user-halfop cuser)
-                  (cond ((eq halfop 'on) t)
-                        ((eq halfop 'off) nil)
-                        (t halfop))))
-          (when (and op
-                     (not (eq (erc-channel-user-op cuser) op)))
-            (setq changed t)
-            (setf (erc-channel-user-op cuser)
-                  (cond ((eq op 'on) t)
-                        ((eq op 'off) nil)
-                        (t op))))
-          (when (and admin
-                     (not (eq (erc-channel-user-admin cuser) admin)))
-            (setq changed t)
-            (setf (erc-channel-user-admin cuser)
-                  (cond ((eq admin 'on) t)
-                        ((eq admin 'off) nil)
-                        (t admin))))
-          (when (and owner
-                     (not (eq (erc-channel-user-owner cuser) owner)))
-            (setq changed t)
-            (setf (erc-channel-user-owner cuser)
-                  (cond ((eq owner 'on) t)
-                        ((eq owner 'off) nil)
-                        (t owner))))
+          (erc--update-cusr-status-if-changed cuser changed voice)
+          (erc--update-cusr-status-if-changed cuser changed halfop)
+          (erc--update-cusr-status-if-changed cuser changed op)
+          (erc--update-cusr-status-if-changed cuser changed admin)
+          (erc--update-cusr-status-if-changed cuser changed owner)
           (when update-message-time
             (setf (erc-channel-user-last-message-time cuser) (current-time)))
           (setq user-changed
@@ -6535,21 +6857,11 @@ See also: `erc-update-user' and 
`erc-update-channel-member'."
                 (cons (current-buffer)
                       (erc-server-user-buffers user))))
         (setq cuser (make-erc-channel-user
-                     :voice (cond ((eq voice 'on) t)
-                                  ((eq voice 'off) nil)
-                                  (t voice))
-                     :halfop (cond ((eq halfop 'on) t)
-                                ((eq halfop 'off) nil)
-                                (t halfop))
-                     :op (cond ((eq op 'on) t)
-                               ((eq op 'off) nil)
-                               (t op))
-                     :admin (cond ((eq admin 'on) t)
-                                  ((eq admin 'off) nil)
-                                  (t admin))
-                     :owner (cond ((eq owner 'on) t)
-                                  ((eq owner 'off) nil)
-                                  (t owner))
+                     :voice  (and (not (eq voice  'off)) (and voice  t))
+                     :halfop (and (not (eq halfop 'off)) (and halfop t))
+                     :op     (and (not (eq op     'off)) (and op     t))
+                     :admin  (and (not (eq admin  'off)) (and admin  t))
+                     :owner  (and (not (eq owner  'off)) (and owner  t))
                      :last-message-time
                      (if update-message-time (current-time))))
         (puthash (erc-downcase nick) (cons user cuser)
@@ -6779,7 +7091,7 @@ Use the getter of the same name to retrieve the current 
value.")
           (ct (make-char-table 'erc--channel-mode-types))
           (type ?a))
       (dolist (cs types)
-        (dolist (c (append cs nil))
+        (erc--doarray (c cs)
           (aset ct c type))
         (cl-incf type))
       (make-erc--channel-mode-types :key key
@@ -6798,21 +7110,20 @@ complement relevant letters in STRING."
          (table (erc--channel-mode-types-table obj))
          (fallbackp (erc--channel-mode-types-fallbackp obj))
          (+p t))
-    (dolist (c (append string nil))
-      (let ((letter (char-to-string c)))
-        (cond ((= ?+ c) (setq +p t))
-              ((= ?- c) (setq +p nil))
-              ((and status-letters (string-search letter status-letters))
-               (erc--update-membership-prefix (pop args) c (if +p 'on 'off)))
-              ((and-let* ((group (or (aref table c) (and fallbackp ?d))))
-                 (erc--handle-channel-mode group c +p
-                                           (and (/= group ?d)
-                                                (or (/= group ?c) +p)
-                                                (pop args)))
-                 t))
-              ((not fallbackp)
-               (erc-display-message nil '(notice error) (erc-server-buffer)
-                                    (format "Unknown channel mode: %S" c))))))
+    (erc--doarray (c string)
+      (cond ((= ?+ c) (setq +p t))
+            ((= ?- c) (setq +p nil))
+            ((and status-letters (string-search (string c) status-letters))
+             (erc--update-membership-prefix (pop args) c (if +p 'on 'off)))
+            ((and-let* ((group (or (aref table c) (and fallbackp ?d))))
+               (erc--handle-channel-mode group c +p
+                                         (and (/= group ?d)
+                                              (or (/= group ?c) +p)
+                                              (pop args)))
+               t))
+            ((not fallbackp)
+             (erc-display-message nil '(notice error) (erc-server-buffer)
+                                  (format "Unknown channel mode: %S" c)))))
     (setq erc-channel-modes (sort erc-channel-modes #'string<))
     (setq erc--mode-line-mode-string
           (concat "+" (erc--channel-modes erc--mode-line-chanmodes-arg-len)))
@@ -6892,9 +7203,7 @@ dropped were they not already absent."
   (let ((addp t)
         ;;
         redundant-add redundant-drop adding dropping)
-    ;; For short strings, `append' appears to be no slower than
-    ;; iteration var + `aref' or `mapc' + closure.
-    (dolist (c (append string nil))
+    (erc--doarray (c string)
       (pcase c
         (?+ (setq addp t))
         (?- (setq addp nil))
@@ -7087,9 +7396,9 @@ EmacsSpeak support."
 (defalias 'erc-list 'ensure-list)
 
 (defconst erc--parse-user-regexp-pedantic
-  (rx bot (group (* (not (any "!\r\n"))))
-      "!" (group (* nonl))
-      "@" (group (* nonl)) eot))
+  (rx bot (? (? (group (+ (not (any "!@\r\n"))))) "!")
+      (? (? (group (+ nonl))) "@")
+      (? (group (+ nonl))) eot))
 
 (defconst erc--parse-user-regexp-legacy
   "^\\([^!\n]*\\)!\\([^@\n]*\\)@\\(.*\\)$")
@@ -7113,6 +7422,16 @@ Return a list of the three separate tokens."
    (t
     (list string "" ""))))
 
+(defun erc--parse-nuh (string)
+  "Match STRING against `erc--parse-user-regexp-pedantic'.
+Return matching groups or nil.  Interpret a lone token or one
+with only a leading \"!\" as a host.  See associated unit test
+for precise behavior."
+  (when (string-match erc--parse-user-regexp-pedantic string)
+    (list (match-string 1 string)
+          (match-string 2 string)
+          (match-string 3 string))))
+
 (defun erc-extract-nick (string)
   "Return the nick corresponding to a user specification STRING.
 
@@ -7285,11 +7604,20 @@ a separate message."
   (when (< (point) (erc-beg-of-input-line))
     "Point is not in the input area"))
 
+;; Originally, `erc-send-current-line' inhibited sends whenever a
+;; server buffer was missing.  In 2007, this was narrowed to
+;; occurrences involving process-dependent commands.  However, the
+;; accompanying error message, which was identical to that emitted by
+;; `erc-server-send', "ERC: No process running", was always inaccurate
+;; because a server buffer can be alive and its process dead.
 (defun erc--check-prompt-input-for-running-process (string _)
-  "Return non-nil unless in an active ERC server buffer."
-  (unless (or (erc-server-buffer-live-p)
-              (erc-command-no-process-p string))
-    "ERC: No process running"))
+  "Return non-nil if STRING is a slash command missing a process.
+Also do so when the server buffer has been killed."
+  ;; Even if the server buffer has been killed, the user should still
+  ;; be able to /reconnect and recall previous commands.
+  (and (not (erc-command-no-process-p string))
+       (or (and (not (erc-server-buffer-live-p)) "Server buffer missing")
+           (and (not (erc-server-process-alive)) "Process not running"))))
 
 (defun erc--check-prompt-input-for-multiline-command (line lines)
   "Return non-nil when non-blank lines follow a command line."
@@ -7406,6 +7734,22 @@ When all lines are empty, remove all but the first."
     (setf (erc--input-split-lines state)
           (mapcan #'erc--split-line (erc--input-split-lines state)))))
 
+(defun erc--input-ensure-hook-context ()
+  (unless (erc--input-split-p erc--current-line-input-split)
+    (error "Invoked outside of `erc-pre-send-functions'")))
+
+(defun erc-input-refoldp (_)
+  "Impersonate accessor for phony `erc-input' `refoldp' slot.
+This function only works inside `erc-pre-send-functions' members."
+  (declare (gv-setter (lambda (v)
+                        `(progn
+                           (erc--input-ensure-hook-context)
+                           (setf (erc--input-split-refoldp
+                                  erc--current-line-input-split)
+                                 ,v)))))
+  (erc--input-ensure-hook-context)
+  (erc--input-split-refoldp erc--current-line-input-split))
+
 (defun erc--run-send-hooks (lines-obj)
   "Run send-related hooks that operate on the entire prompt input.
 Sequester some of the back and forth involved in honoring old
@@ -7425,8 +7769,6 @@ queue.  Expect LINES-OBJ to be an `erc--input-split' 
object."
                       (run-hook-with-args 'erc-send-pre-hook str)
                       (make-erc-input :string str
                                       :insertp erc-insert-this
-                                      :refoldp (erc--input-split-refoldp
-                                                lines-obj)
                                       :sendp erc-send-this))))
         (run-hook-with-args 'erc-pre-send-functions state)
         (setf (erc--input-split-sendp lines-obj) (erc-input-sendp state)
@@ -7438,7 +7780,7 @@ queue.  Expect LINES-OBJ to be an `erc--input-split' 
object."
                 (if erc--allow-empty-outgoing-lines-p
                     lines
                   (cl-nsubst " " "" lines :test #'equal))))
-        (when (erc-input-refoldp state)
+        (when (erc--input-split-refoldp lines-obj)
           (erc--split-lines lines-obj)))))
   (when (and (erc--input-split-cmdp lines-obj)
              (cdr (erc--input-split-lines lines-obj)))
@@ -7518,15 +7860,11 @@ as outgoing chat messages and echoed slash commands."
       (erc--assert-input-bounds)
       (let ((insert-position (marker-position (goto-char erc-insert-marker)))
             (erc--msg-props (or erc--msg-props
-                                (let ((ovs erc--msg-prop-overrides))
-                                  (map-into `((erc-msg . msg) ,@(reverse ovs))
-                                            'hash-table))))
-            beg)
-        (insert (erc-format-my-nick))
-        (setq beg (point))
-        (insert line)
-        (erc-put-text-property beg (point) 'font-lock-face 'erc-input-face)
-        (insert "\n")
+                                (let ((ovs (seq-filter
+                                            #'cdr erc--msg-prop-overrides)))
+                                  (map-into `((erc--msg . msg) ,@(reverse ovs))
+                                            'hash-table)))))
+        (insert (erc--format-speaker-input-message line) "\n")
         (save-restriction
           (narrow-to-region insert-position (point))
           (run-hooks 'erc-send-modify-hook)
@@ -7671,6 +8009,8 @@ The previous default target of QUERY type gets removed."
         (setq erc-default-recipients d2)
       (error "Current target is not a QUERY"))))
 
+;; FIXME move all ignore-related functionality to its own module,
+;; required and enabled by default (until some major version change).
 (defun erc-ignored-user-p (spec)
   "Return non-nil if SPEC matches something in `erc-ignore-list'.
 
@@ -8288,8 +8628,13 @@ See `erc-mode-line-format' for which characters are can 
be used."
   :type '(choice (const :tag "Disabled" nil)
                  string))
 
+;; This should optionally support the built-in `tab-bar'.
 (defcustom erc-header-line-uses-tabbar-p nil
-  "Use tabbar mode instead of the header line to display the header."
+  "Use `tabbar-mode' integration instead of the header line.
+This concerns a historical integration with the external library
+`tabbar' <https://www.emacswiki.org/emacs/tabbar.el>, which
+shouldn't be confused with the built-in `tab-bar' described in
+Info node `(emacs) Tab Bars'."
   :group 'erc-mode-line-and-header
   :type 'boolean)
 
@@ -8425,7 +8770,7 @@ Currently only used by the option `erc-prompt-format'.")
 (defun erc--format-channel-status-prefix ()
   "Return the current channel membership prefix."
   (and (erc--target-channel-p erc--target)
-       (erc-get-user-mode-prefix (erc-current-nick))))
+       (erc-get-channel-membership-prefix (erc-current-nick))))
 
 (defun erc--format-modes (&optional no-query-p)
   "Return a string of channel modes in channels and user modes elsewhere.
@@ -8496,7 +8841,8 @@ buffers.  Also return nil when mode information is 
unavailable."
                         (format-spec erc-header-line-format spec)
                       nil)))
         (cond (erc-header-line-uses-tabbar-p
-               (setq-local tabbar--local-hlf header-line-format)
+               (when (boundp 'tabbar--local-hlf)
+                 (setq-local tabbar--local-hlf header-line-format))
                (kill-local-variable 'header-line-format))
               ((null header)
                (setq header-line-format nil))
@@ -8690,24 +9036,38 @@ All windows are opened in the current frame."
 
 ;;; Message catalog
 
+(define-inline erc--make-message-variable-name (catalog key softp)
+  "Return variable name conforming to ERC's message-catalog interface.
+Given a CATALOG symbol `mycat' and format-string KEY `mykey',
+also a symbol, return the symbol `erc-message-mycat-mykey'.  With
+SOFTP, only do so when defined as a variable."
+  (inline-quote
+   (let* ((catname (symbol-name ,catalog))
+          (prefix (if (eq ?- (aref catname 0)) "erc--message" "erc-message-"))
+          (name (concat prefix catname "-" (symbol-name ,key))))
+     (if ,softp
+         (and-let* ((s (intern-soft name)) ((boundp s))) s)
+       (intern name)))))
+
 (defun erc-make-message-variable-name (catalog entry)
   "Create a variable name corresponding to CATALOG's ENTRY."
-  (intern (concat "erc-message-"
-                  (symbol-name catalog) "-" (symbol-name entry))))
+  (erc--make-message-variable-name catalog entry nil))
 
 (defun erc-define-catalog-entry (catalog entry format-spec)
   "Set CATALOG's ENTRY to FORMAT-SPEC."
+  (declare (obsolete "define manually using `defvar' instead" "30.1"))
   (set (erc-make-message-variable-name catalog entry)
        format-spec))
 
 (defun erc-define-catalog (catalog entries)
   "Define a CATALOG according to ENTRIES."
-  (dolist (entry entries)
-    (erc-define-catalog-entry catalog (car entry) (cdr entry))))
+  (declare (obsolete erc-define-message-format-catalog "30.1"))
+  (with-suppressed-warnings ((obsolete erc-define-catalog-entry))
+    (dolist (entry entries)
+      (erc-define-catalog-entry catalog (car entry) (cdr entry)))))
 
-(erc-define-catalog
- 'english
- '((bad-ping-response . "Unexpected PING response from %n (time %t)")
+(erc--define-catalog english
+  ((bad-ping-response . "Unexpected PING response from %n (time %t)")
    (bad-syntax . "Error occurred - incorrect usage?\n%c %u\n%d")
    (incorrect-args . "Incorrect arguments. Usage:\n%c %u\n%d")
    (cannot-find-file . "Cannot find file %f")
@@ -8764,7 +9124,7 @@ All windows are opened in the current frame."
    (MODE-nick . "%n has changed mode for %t to %m")
    (NICK   . "%n (%u@%h) is now known as %N")
    (NICK-you . "Your new nickname is %N")
-   (PART   . erc-message-english-PART)
+   (PART   . #'erc-message-english-PART)
    (PING   . "PING from server (last: %s sec. ago)")
    (PONG   . "PONG from %h (%i second%s)")
    (QUIT   . "%n (%u@%h) has quit: %r")
@@ -8806,6 +9166,7 @@ All windows are opened in the current frame."
    (s368   . "Banlist of %c ends.")
    (s379   . "%c: Forwarded to %f")
    (s391   . "The time at %s is %t")
+   (s396   . "Your visible host has changed to %s")
    (s401   . "%n: No such nick/channel")
    (s402   . "%c: No such server")
    (s403   . "%c: No such channel")
@@ -8858,22 +9219,20 @@ functions."
                           (string-replace "%" "%%" reason))
                 "")))))
 
-
-(defvar-local erc-current-message-catalog 'english)
-
-(defun erc-retrieve-catalog-entry (entry &optional catalog)
-  "Retrieve ENTRY from CATALOG.
-
-If CATALOG is nil, `erc-current-message-catalog' is used.
-
-If ENTRY is nil in CATALOG, it is retrieved from the fallback,
-english, catalog."
+(defun erc-retrieve-catalog-entry (key &optional catalog)
+  "Retrieve `format-spec' entry for symbol KEY in CATALOG.
+Without symbol CATALOG, use `erc-current-message-catalog'.  If
+lookup fails, try the latter's `default-toplevel-value' if it's
+not the same as CATALOG.  Failing that, try the `english' catalog
+if yet untried."
   (unless catalog (setq catalog erc-current-message-catalog))
-  (let ((var (erc-make-message-variable-name catalog entry)))
-    (if (boundp var)
-        (symbol-value var)
-      (when (boundp (erc-make-message-variable-name 'english entry))
-        (symbol-value (erc-make-message-variable-name 'english entry))))))
+  (symbol-value
+   (or (erc--make-message-variable-name catalog key 'softp)
+       (let ((default (default-toplevel-value 'erc-current-message-catalog)))
+         (or (and (not (eq default catalog))
+                  (erc--make-message-variable-name default key 'softp))
+             (and (not (memq 'english (list default catalog)))
+                  (erc--make-message-variable-name 'english key 'softp)))))))
 
 (defun erc-format-message (msg &rest args)
   "Format MSG according to ARGS.
diff --git a/lisp/eshell/em-hist.el b/lisp/eshell/em-hist.el
index cf03f8399a6..9b1bc009079 100644
--- a/lisp/eshell/em-hist.el
+++ b/lisp/eshell/em-hist.el
@@ -116,6 +116,12 @@ If set to t, history will always be saved, silently."
                 (const :tag "Ask" ask)
                 (const :tag "Always save" t)))
 
+(defcustom eshell-history-append nil
+  "If non-nil, append new entries to the history file when saving history."
+  :type '(choice (const :tag "Overwrite history file" nil)
+                (const :tag "Append new entries to file" t))
+  :version "30.1")
+
 (defcustom eshell-input-filter 'eshell-input-filter-default
   "Predicate for filtering additions to input history.
 Takes one argument, the input.  If non-nil, the input may be saved on
@@ -294,17 +300,21 @@ Returns nil if INPUT is prepended by blank space, 
otherwise non-nil."
     (if eshell-history-file-name
        (eshell-read-history nil t))
 
-    (add-hook 'eshell-exit-hook #'eshell-write-history nil t))
+    (add-hook 'eshell-exit-hook #'eshell--save-history nil t))
 
   (unless eshell-history-ring
     (setq eshell-history-ring (make-ring eshell-history-size)))
 
-  (add-hook 'eshell-exit-hook #'eshell-write-history nil t)
+  (add-hook 'eshell-exit-hook #'eshell--save-history nil t)
 
   (add-hook 'kill-emacs-query-functions #'eshell-save-some-history)
 
   (add-hook 'eshell-input-filter-functions #'eshell-add-to-history nil t))
 
+(defun eshell--save-history ()
+  "Save the history for current Eshell buffer."
+  (eshell-write-history nil eshell-history-append))
+
 (defun eshell-save-some-history ()
   "Save the history for any open Eshell buffers."
   (dolist (buf (buffer-list))
@@ -318,7 +328,7 @@ Returns nil if INPUT is prepended by blank space, otherwise 
non-nil."
                        (format-message
                         "Save input history for Eshell buffer `%s'? "
                         (buffer-name buf)))))
-             (eshell-write-history)))))
+             (eshell--save-history)))))
   t)
 
 (defun eshell/history (&rest args)
@@ -389,7 +399,7 @@ input."
                ('nil t)                 ; Always add to history
                ('erase                  ; Add, removing any old occurrences
                 (when-let ((old-index (ring-member eshell-history-ring input)))
-                  ;; Remove the old occurence of this input so we can
+                  ;; Remove the old occurrence of this input so we can
                   ;; add it to the end.  FIXME: Should we try to
                   ;; remove multiple old occurrences, e.g. if the user
                   ;; recently changed to using `erase'?
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 509b2d31819..67e5bda021b 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -92,7 +92,7 @@ Otherwise, `rmdir' is required."
   :group 'eshell-unix)
 
 (define-widget 'eshell-interactive-query 'radio
-  "When to interatively query the user about a particular operation.
+  "When to interactively query the user about a particular operation.
 If t, always query.  If nil, never query.  If `root', query when
 the user is logged in as root (including when `default-directory'
 is remote with a root user)."
diff --git a/lisp/files-x.el b/lisp/files-x.el
index a8d525ec5ff..41d9cd3bab8 100644
--- a/lisp/files-x.el
+++ b/lisp/files-x.el
@@ -791,6 +791,7 @@ definitions that aren't listed in VARIABLES."
     (setq variables (nreverse existing-variables)))
   (connection-local-set-profile-variables profile variables))
 
+;;;###autoload
 (defun hack-connection-local-variables (criteria)
   "Read connection-local variables according to CRITERIA.
 Store the connection-local variables in buffer local
@@ -925,18 +926,47 @@ earlier in the `setq-connection-local'.  The return value 
of the
           connection-local-criteria
           connection-local-profile-name-for-setq)))))
 
+;;;###autoload
+(defmacro connection-local-p (variable &optional application)
+  "Non-nil if VARIABLE has a connection-local binding in `default-directory'.
+If APPLICATION is nil, the value of
+`connection-local-default-application' is used."
+  (declare (debug (symbolp &optional form)))
+  (unless (symbolp variable)
+    (signal 'wrong-type-argument (list 'symbolp variable)))
+  `(let (connection-local-variables-alist file-local-variables-alist)
+     (hack-connection-local-variables
+      (connection-local-criteria-for-default-directory ,application))
+     (and (assq ',variable connection-local-variables-alist) t)))
+
+;;;###autoload
+(defmacro connection-local-value (variable &optional application)
+  "Return connection-local VARIABLE for APPLICATION in `default-directory'.
+If APPLICATION is nil, the value of
+`connection-local-default-application' is used.
+If VARIABLE does not have a connection-local binding, the return
+value is the default binding of the variable."
+  (declare (debug (symbolp &optional form)))
+  (unless (symbolp variable)
+    (signal 'wrong-type-argument (list 'symbolp variable)))
+  `(let (connection-local-variables-alist file-local-variables-alist)
+     (hack-connection-local-variables
+      (connection-local-criteria-for-default-directory ,application))
+     (if-let ((result (assq ',variable connection-local-variables-alist)))
+         (cdr result)
+       ,variable)))
+
 ;;;###autoload
 (defun path-separator ()
   "The connection-local value of `path-separator'."
-  (with-connection-local-variables path-separator))
+  (connection-local-value path-separator))
 
 ;;;###autoload
 (defun null-device ()
   "The connection-local value of `null-device'."
-  (with-connection-local-variables null-device))
+  (connection-local-value null-device))
 
 
-
 (provide 'files-x)
 
 ;;; files-x.el ends here
diff --git a/lisp/files.el b/lisp/files.el
index 5b44f8824d9..1b1d45876fc 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -7085,11 +7085,19 @@ auto-save file, if that is more recent than the visited 
file."
            #'(lambda (window _value)
                (with-selected-window window
                  (unwind-protect
-                     (yes-or-no-p (format "Recover auto save file %s? " 
file-name))
+                      (let ((prompt (format "Recover auto save file %s? " 
file-name))
+                            (choices
+                             '(("yes" ?y "recover auto save file")
+                               ("no" ?n "don't recover auto save file")
+                               ("diff" ?= "show changes between auto save file 
and current file")))
+                            ans)
+                        (while (equal "diff" (setq ans (read-answer prompt 
choices)))
+                          (diff file file-name))
+                        (equal ans "yes"))
                    (when (window-live-p window)
                      (quit-restore-window window 'kill)))))
            (with-current-buffer standard-output
-             (let ((switches dired-listing-switches))
+             (let ((switches (connection-local-value dired-listing-switches)))
                (if (file-symlink-p file)
                    (setq switches (concat switches " -L")))
                ;; Use insert-directory-safely, not insert-directory,
@@ -7141,7 +7149,7 @@ Then you'll be asked about a number of files to recover."
         ;; hook.
         (dired-mode-hook (delete 'dired-omit-mode dired-mode-hook)))
     (dired (concat auto-save-list-file-prefix "*")
-          (concat dired-listing-switches " -t")))
+          (concat (connection-local-value dired-listing-switches) " -t")))
   (use-local-map (nconc (make-sparse-keymap) (current-local-map)))
   (define-key (current-local-map) "\C-c\C-c" 'recover-session-finish)
   (save-excursion
diff --git a/lisp/filesets.el b/lisp/filesets.el
index 639b108ac03..8e7ddab8c1c 100644
--- a/lisp/filesets.el
+++ b/lisp/filesets.el
@@ -1648,7 +1648,17 @@ Assume MODE (see `filesets-entry-mode'), if provided."
                                (filesets-entry-get-master entry)))))
                  (cons entry (filesets-ingroup-cache-get entry))))
               (:tree
-                (let* ((dirpatt (filesets-entry-get-tree entry))
+                ;; Warning: ENTRY here could be of at least two
+                ;; differente forms, either
+                ;;    (NAME (:tree DIRECTORY PATTERN))
+                ;; or
+                ;;    (DIRECTORY PATTERN)
+                ;; The latter happens when opening a tree fileset
+                ;; from the Filesets menu.  We need to support both
+                ;; of these forms!
+                (let* ((dirpatt (if (consp (nth 1 entry))
+                                    (filesets-entry-get-tree entry)
+                                  entry))
                        (dir (nth 0 dirpatt))
                        (patt (nth 1 dirpatt))
                        (depth (or (filesets-entry-get-tree-max-level entry)
diff --git a/lisp/gnus/ChangeLog.1 b/lisp/gnus/ChangeLog.1
index 2ce954cca99..d4d5a819c9f 100644
--- a/lisp/gnus/ChangeLog.1
+++ b/lisp/gnus/ChangeLog.1
@@ -663,7 +663,7 @@
 1998-08-07  Gareth Jones  <gdj1@gdjones.demon.co.uk>
 
        * gnus-score.el (gnus-summary-increase-score): Don't downcase
-       before lookin in char-to-header.
+       before looking in char-to-header.
 
 1998-08-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
 
@@ -2745,7 +2745,7 @@
 
 1997-12-05  Dave Love  <d.love@dl.ac.uk>
 
-       * gnus-nocem.el (gnus-nocem-message-wanted-p): Fix paren typpo.
+       * gnus-nocem.el (gnus-nocem-message-wanted-p): Fix paren typo.
        (gnus-nocem-issuers): Allow sexp alternative in :type for alists.
 
 1997-12-05  Dave Love  <d.love@dl.ac.uk>
diff --git a/lisp/gnus/ChangeLog.2 b/lisp/gnus/ChangeLog.2
index 2d7aeabd8cf..ffa94b739fa 100644
--- a/lisp/gnus/ChangeLog.2
+++ b/lisp/gnus/ChangeLog.2
@@ -6215,7 +6215,7 @@
        * pop3.el (pop3-retr): Wait 500 msecs.
        (pop3-read-response): Ditto.
 
-       * gnus-msg.el (gnus-setup-message): Get the evaliation order
+       * gnus-msg.el (gnus-setup-message): Get the evaluation order
        right.
        (gnus-inews-make-draft): New function.
        (gnus-setup-message): Use it.
@@ -9474,7 +9474,7 @@
 2002-03-01  Paul Jarc  <prj@po.cwru.edu>
 
        * message.el (message-get-reply-headers): Downcase email addresses
-       for comaparisons for duplicate removal.
+       for comparisons for duplicate removal.
 
 2002-03-01  ShengHuo ZHU  <zsh@cs.rochester.edu>
 
diff --git a/lisp/gnus/ChangeLog.3 b/lisp/gnus/ChangeLog.3
index 0fc5c093371..5005e56f5e9 100644
--- a/lisp/gnus/ChangeLog.3
+++ b/lisp/gnus/ChangeLog.3
@@ -13,7 +13,7 @@
 
 2015-04-01  Eric Abrahamsen  <eric@ericabrahamsen.net>
 
-       * registry.el (registry-prune): Re-use `registry-full' in
+       * registry.el (registry-prune): Reuse `registry-full' in
        `registry-prune'.  It's a bit of redundant work, but safer.
        Also ensure that target-size is an integer.
 
@@ -78,7 +78,7 @@
        * gnus-notifications.el (gnus-notifications-action): Raise window
        frame.
        (gnus-notifications-action): Allow mark as read.
-       (gnus-notifications-notify): Show uption to mark as read.
+       (gnus-notifications-notify): Show option to mark as read.
 
 2015-03-08  Adam Sjøgren  <asjo@koldfront.dk>
 
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index bd9a49eb6a5..b4abb3680cb 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -2871,12 +2871,15 @@ Return file name relative to the parent of DIRECTORY."
                              cid handle directory))
              (throw 'found file)))
           ((equal (concat "<" cid ">") (mm-handle-id handle))
-           (setq file (or (mm-handle-filename handle)
-                          (concat
-                           (make-temp-name "cid")
-                           (car (rassoc (car (mm-handle-type handle))
-                                        mailcap-mime-extensions))))
-                 afile (expand-file-name file directory))
+            ;; Randomize filenames: declared filenames may not be unique.
+            (setq file (format "cid-%d-%s"
+                              (random 99)
+                              (or (mm-handle-filename handle)
+                                  (concat
+                                   (make-temp-name "cid")
+                                   (car (rassoc (car (mm-handle-type handle))
+                                                mailcap-mime-extensions)))))
+                  afile (expand-file-name file directory))
            (mm-save-part-to-file handle afile)
            (throw 'found (concat (file-name-nondirectory
                                   (directory-file-name directory))
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 9a1a6f9b27d..a9c38334933 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -1755,33 +1755,35 @@ current line is also eligible as a target."
        (low gnus-level-killed)
        (beg (point))
        pos found lev)
-    (unless first-too
-      (forward-line way))
-    (while (and
-           (not (if backward (bobp) (eobp)))
-           (not (setq
-                 found
-                 (and
-                  (get-text-property (point) 'gnus-group)
-                  (or all
-                      (and
-                       (let ((unread
-                              (get-text-property (point) 'gnus-unread)))
-                         (and (numberp unread) (> unread 0)))
-                       (setq lev (get-text-property (point)
-                                                    'gnus-level))
-                       (<= lev gnus-level-subscribed)))
-                  (or (not level)
-                      (and (setq lev (get-text-property (point)
-                                                        'gnus-level))
-                           (or (= lev level)
-                               (and (< lev low)
-                                    (< level lev)
-                                    (progn
-                                      (setq low lev)
-                                      (setq pos (point))
-                                      nil))))))))
-           (zerop (forward-line way))))
+    (if (and backward (progn (beginning-of-line) (bobp)))
+       nil
+      (unless first-too
+       (forward-line way))
+      (while (and
+             (not (eobp))
+             (not (setq
+                   found
+                   (and
+                    (get-text-property (point) 'gnus-group)
+                    (or all
+                        (and
+                         (let ((unread
+                                (get-text-property (point) 'gnus-unread)))
+                           (and (numberp unread) (> unread 0)))
+                         (setq lev (get-text-property (point)
+                                                      'gnus-level))
+                         (<= lev gnus-level-subscribed)))
+                    (or (not level)
+                        (and (setq lev (get-text-property (point)
+                                                          'gnus-level))
+                             (or (= lev level)
+                                 (and (< lev low)
+                                      (< level lev)
+                                      (progn
+                                        (setq low lev)
+                                        (setq pos (point))
+                                        nil))))))))
+             (zerop (forward-line way)))))
     (if found
        (progn (gnus-group-position-point) t)
       (goto-char (or pos beg))
diff --git a/lisp/gnus/gnus-msg.el b/lisp/gnus/gnus-msg.el
index b065ae34851..e503ccae00f 100644
--- a/lisp/gnus/gnus-msg.el
+++ b/lisp/gnus/gnus-msg.el
@@ -1209,7 +1209,7 @@ The original article(s) will be yanked."
   (gnus-summary-reply
    (gnus-summary-work-articles n) t (gnus-summary-work-articles n)))
 
-(defun gnus-summary-mail-forward (&optional arg post)
+(defun gnus-summary-mail-forward (&optional arg all-headers post)
   "Forward the current message(s) to another user.
 If process marks exist, forward all marked messages;
 if ARG is nil, see `message-forward-as-mime' and `message-forward-show-mml';
@@ -1217,17 +1217,25 @@ if ARG is 1, decode the message and forward directly 
inline;
 if ARG is 2, forward message as an rfc822 MIME section;
 if ARG is 3, decode message and forward as an rfc822 MIME section;
 if ARG is 4, forward message directly inline;
-otherwise, use flipped `message-forward-as-mime'.
+otherwise, use negated `message-forward-as-mime'.
 If POST, post instead of mail.
-For the \"inline\" alternatives, also see the variable
-`message-forward-ignored-headers'."
-  (interactive "P" gnus-summary-mode)
+If symbolic prefix ALL-HEADERS is the symbol `a', include all
+original headers in the forwarded message, except those matching
+`message-forward-ignored-headers'.  Otherwise, include headers
+based on the options `message-forward-included-headers',
+`message-forward-ignored-headers', and potentially
+`message-forward-included-mime-headers'."
+  (interactive (gnus-interactive "P\ny") gnus-summary-mode)
   (if (cdr (gnus-summary-work-articles nil))
       ;; Process marks are given.
       (gnus-uu-digest-mail-forward nil post)
     ;; No process marks.
     (let ((message-forward-as-mime message-forward-as-mime)
-         (message-forward-show-mml message-forward-show-mml))
+         (message-forward-show-mml message-forward-show-mml)
+          (message-forward-included-headers
+           (if (eq all-headers 'a)
+               nil
+             message-forward-included-headers)))
       (cond
        ((null arg))
        ((eq arg 1)
@@ -1380,11 +1388,11 @@ composing a new message."
          (forward-char 1))
        (widen)))))
 
-(defun gnus-summary-post-forward (&optional arg)
+(defun gnus-summary-post-forward (&optional arg all-headers)
   "Forward the current article to a newsgroup.
 See `gnus-summary-mail-forward' for ARG."
-  (interactive "P" gnus-summary-mode)
-  (gnus-summary-mail-forward arg t))
+  (interactive (gnus-interactive "P\ny") gnus-summary-mode)
+  (gnus-summary-mail-forward arg all-headers t))
 
 (defun gnus-summary-mail-crosspost-complaint (n)
   "Send a complaint about crossposting to the current article(s)."
diff --git a/lisp/gnus/gnus-search.el b/lisp/gnus/gnus-search.el
index 839e5d203ff..282afaeb540 100644
--- a/lisp/gnus/gnus-search.el
+++ b/lisp/gnus/gnus-search.el
@@ -1450,7 +1450,7 @@ Returns a list of [group article score] vectors."
        (when (and f-name
                    (file-readable-p f-name)
                   (null (file-directory-p f-name)))
-          ;; `expand-file-name' canoncalizes the file name,
+          ;; `expand-file-name' canonicalizes the file name,
           ;; specifically collapsing multiple consecutive directory
           ;; separators.
           (setq f-name (expand-file-name f-name)
diff --git a/lisp/gnus/message.el b/lisp/gnus/message.el
index 9e60c21e3d4..fae7342eb09 100644
--- a/lisp/gnus/message.el
+++ b/lisp/gnus/message.el
@@ -1876,9 +1876,13 @@ downcased."
   :type '(repeat (repeat string)))
 
 (defcustom message-mail-user-agent nil
-  "Like `mail-user-agent'.
-Except if it is nil, use Gnus native MUA; if it is t, use
-`mail-user-agent'."
+  "Your preferred package for composing and sending email when using 
message.el.
+Like `mail-user-agent' (which see), this specifies the package you prefer
+to use for composing and sending email messages.
+The value can be anything accepted by `mail-user-agent', and in addition
+it can be nil or t.  If the value is nil, use the Gnus native Mail User
+Agent (MUA); if it is t, use the value of `mail-user-agent'.
+For more about mail user agents, see Info node `(emacs)Mail Methods'"
   :version "22.1"
   :type '(radio (const :tag "Gnus native"
                       :format "%t\n"
diff --git a/lisp/gnus/nndiary.el b/lisp/gnus/nndiary.el
index 8728aab1def..be1a4056154 100644
--- a/lisp/gnus/nndiary.el
+++ b/lisp/gnus/nndiary.el
@@ -1030,7 +1030,7 @@ all.  This may very well take some time.")
 (defun nndiary-generate-nov-databases (&optional server)
   "Generate NOV databases in all nndiary directories."
   (interactive (list (or (nnoo-current-server 'nndiary) "")))
-  ;; Read the active file to make sure we don't re-use articles
+  ;; Read the active file to make sure we don't reuse articles
   ;; numbers in empty groups.
   (nnmail-activate 'nndiary)
   (unless (nndiary-server-opened server)
diff --git a/lisp/gnus/nnml.el b/lisp/gnus/nnml.el
index d969716f020..44962c61b4b 100644
--- a/lisp/gnus/nnml.el
+++ b/lisp/gnus/nnml.el
@@ -830,7 +830,7 @@ article number.  This function is called narrowed to an 
article."
 (defun nnml-generate-nov-databases (&optional server)
   "Generate NOV databases in all nnml directories."
   (interactive (list (or (nnoo-current-server 'nnml) "")))
-  ;; Read the active file to make sure we don't re-use articles
+  ;; Read the active file to make sure we don't reuse articles
   ;; numbers in empty groups.
   (nnmail-activate 'nnml)
   (unless (nnml-server-opened server)
diff --git a/lisp/indent.el b/lisp/indent.el
index f856f0c9ab5..80ddbebf8ad 100644
--- a/lisp/indent.el
+++ b/lisp/indent.el
@@ -265,7 +265,7 @@ indentation by specifying a large negative ARG."
   (interactive "r\nP\np")
   (if (and (not arg) interactive)
       (set-transient-map indent-rigidly-map t #'deactivate-mark
-                         "Indent region with %k")
+                         "Type %k to indent region interactively")
     (save-excursion
       (goto-char end)
       (setq end (point-marker))
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index 849a8d8eaee..f5db3674366 100644
--- a/lisp/jsonrpc.el
+++ b/lisp/jsonrpc.el
@@ -4,7 +4,7 @@
 
 ;; Author: João Távora <joaotavora@gmail.com>
 ;; Keywords: processes, languages, extensions
-;; Version: 1.0.18
+;; Version: 1.0.20
 ;; Package-Requires: ((emacs "25.2"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -51,6 +51,7 @@
 (defclass jsonrpc-connection ()
   ((name
     :accessor jsonrpc-name
+    :initform "anonymous"
     :initarg :name
     :documentation "A name for the connection")
    (-request-dispatcher
@@ -76,6 +77,7 @@
     :accessor jsonrpc--events-buffer
     :documentation "A buffer pretty-printing the JSONRPC events")
    (-events-buffer-scrollback-size
+    :initform nil
     :initarg :events-buffer-scrollback-size
     :accessor jsonrpc--events-buffer-scrollback-size
     :documentation "Max size of events buffer.  0 disables, nil means 
infinite.")
@@ -131,6 +133,38 @@ immediately."
   (:method (_s _what)   ;; by default all connections are ready
            t))
 
+;;; API optional
+(cl-defgeneric jsonrpc-convert-to-endpoint (connection message subtype)
+  "Convert MESSAGE to JSONRPCesque message accepted by endpoint.
+MESSAGE is a plist, jsonrpc.el's internal representation of a
+JSONRPC message.  SUBTYPE is one of `request', `reply' or
+`notification'.
+
+Return a plist to be serialized to JSON with `json-serialize' and
+transmitted to endpoint."
+  ;; TODO: describe representations and serialization in manual and
+  ;; link here.
+  (:method (_s message subtype)
+           `(:jsonrpc "2.0"
+                      ,@(if (eq subtype 'reply)
+                            ;; true JSONRPC doesn't have `method'
+                            ;; fields in responses.
+                            (cl-loop for (k v) on message by #'cddr
+                                     unless (eq k :method)
+                                     collect k and collect v)
+                          message))))
+
+;;; API optional
+(cl-defgeneric jsonrpc-convert-from-endpoint (connection remote-message)
+  "Convert JSONRPC-esque REMOTE-MESSAGE to a plist.
+REMOTE-MESSAGE is a plist read with `json-parse'.
+
+Return a plist of jsonrpc.el's internal representation of a
+JSONRPC message."
+  ;; TODO: describe representations and serialization in manual and
+  ;; link here.
+  (:method (_s remote-message) remote-message))
+
 
 ;;; Convenience
 ;;;
@@ -158,7 +192,7 @@ immediately."
 (defvar jsonrpc-inhibit-debug-on-error nil
   "Inhibit `debug-on-error' when answering requests.
 Some extensions, notably ert.el, set `debug-on-error' to non-nil,
-which makes it hard to test the behaviour of catching the Elisp
+which makes it hard to test the behavior of catching the Elisp
 error and replying to the endpoint with an JSONRPC-error.  This
 variable can be set around calls like `jsonrpc-request' to
 circumvent that.")
@@ -168,9 +202,12 @@ circumvent that.")
 This function will destructure MESSAGE and call the appropriate
 dispatcher in CONNECTION."
   (cl-destructuring-bind (&key method id error params result _jsonrpc)
-      message
+      (jsonrpc-convert-from-endpoint connection message)
+    (jsonrpc--log-event connection message 'server
+                        (cond ((and method id)       'request)
+                              (method                'notification)
+                              (id                    'reply)))
     (let (continuations)
-      (jsonrpc--log-event connection message 'server)
       (setf (jsonrpc-last-error connection) error)
       (cond
        (;; A remote request
@@ -191,7 +228,7 @@ dispatcher in CONNECTION."
                                         "Internal error")))))
                   (error
                    '(:error (:code -32603 :message "Internal error"))))))
-          (apply #'jsonrpc--reply connection id reply)))
+          (apply #'jsonrpc--reply connection id method reply)))
        (;; A remote notification
         method
         (funcall (jsonrpc--notification-dispatcher connection)
@@ -363,16 +400,20 @@ ignored."
     :accessor jsonrpc--on-shutdown
     :initform #'ignore
     :initarg :on-shutdown
-    :documentation "Function run when the process dies."))
+    :documentation "Function run when the process dies.")
+   (-autoport-inferior
+    :initform nil
+    :documentation "Used by `jsonrpc-autoport-bootstrap'."))
   :documentation "A JSONRPC connection over an Emacs process.
 The following initargs are accepted:
 
 :PROCESS (mandatory), a live running Emacs process object or a
-function of no arguments producing one such object.  The process
-represents either a pipe connection to locally running process or
-a stream connection to a network host.  The remote endpoint is
-expected to understand JSONRPC messages with basic HTTP-style
-enveloping headers such as \"Content-Length:\".
+function producing one such object.  If a function, it is passed
+the `jsonrpc-process-connection' object.  The process represents
+either a pipe connection to locally running process or a stream
+connection to a network host.  The remote endpoint is expected to
+understand JSONRPC messages with basic HTTP-style enveloping
+headers such as \"Content-Length:\".
 
 :ON-SHUTDOWN (optional), a function of one argument, the
 connection object, called when the process dies.")
@@ -387,37 +428,22 @@ connection object, called when the process dies.")
     ;; could use a pipe with a process filter instead of
     ;; `after-change-functions'.  Alternatively, we need a new initarg
     ;; (but maybe not a slot).
-    (let ((calling-buffer (current-buffer)))
-      (with-current-buffer (get-buffer-create (format "*%s stderr*" name))
-        (let ((inhibit-read-only t)
-              (hidden-name (concat " " (buffer-name))))
-          (erase-buffer)
-          (buffer-disable-undo)
-          (add-hook
-           'after-change-functions
-           (lambda (beg _end _pre-change-len)
-             (cl-loop initially (goto-char beg)
-                      do (forward-line)
-                      when (bolp)
-                      for line = (buffer-substring
-                                  (line-beginning-position 0)
-                                  (line-end-position 0))
-                      do (with-current-buffer (jsonrpc-events-buffer conn)
-                           (goto-char (point-max))
-                           (let ((inhibit-read-only t))
-                             (insert (format "[stderr] %s\n" line))))
-                      until (eobp)))
-           nil t)
-          ;; If we are correctly coupled to the client, the process
-          ;; now created should pick up the current stderr buffer,
-          ;; which we immediately rename
-          (setq proc (if (functionp proc)
-                         (with-current-buffer calling-buffer (funcall proc))
-                       proc))
-          (ignore-errors (kill-buffer hidden-name))
-          (rename-buffer hidden-name)
-          (process-put proc 'jsonrpc-stderr (current-buffer))
-          (setq buffer-read-only t))))
+    (let* ((stderr-buffer-name (format "*%s stderr*" name))
+           (stderr-buffer (jsonrpc--forwarding-buffer stderr-buffer-name 
"[stderr]" conn))
+           (hidden-name (concat " " stderr-buffer-name)))
+      ;; If we are correctly coupled to the client, the process now
+      ;; created should pick up the `stderr-buffer' just created, which
+      ;; we immediately rename
+      (setq proc (if (functionp proc)
+                     (if (zerop (cdr (func-arity proc)))
+                         (funcall proc)
+                       (funcall proc conn))
+                   proc))
+      (with-current-buffer stderr-buffer
+        (ignore-errors (kill-buffer hidden-name))
+        (rename-buffer hidden-name)
+        (setq buffer-read-only t))
+      (process-put proc 'jsonrpc-stderr stderr-buffer))
     (setf (jsonrpc--process conn) proc)
     (set-process-buffer proc (get-buffer-create (format " *%s output*" name)))
     (set-process-filter proc #'jsonrpc--process-filter)
@@ -433,29 +459,34 @@ connection object, called when the process dies.")
 (cl-defmethod jsonrpc-connection-send ((connection jsonrpc-process-connection)
                                        &rest args
                                        &key
-                                       _id
+                                       id
                                        method
                                        _params
-                                       _result
-                                       _error
+                                       (_result nil result-supplied-p)
+                                       error
                                        _partial)
   "Send MESSAGE, a JSON object, to CONNECTION."
   (when method
     (plist-put args :method
                (cond ((keywordp method) (substring (symbol-name method) 1))
-                     ((and method (symbolp method)) (symbol-name method)))))
-  (let* ( (message `(:jsonrpc "2.0" ,@args))
-          (json (jsonrpc--json-encode message))
-          (headers
-           `(("Content-Length" . ,(format "%d" (string-bytes json)))
-             ;; ("Content-Type" . "application/vscode-jsonrpc; charset=utf-8")
-             )))
+                     ((symbolp method) (symbol-name method))
+                     ((stringp method) method)
+                     (t (error "[jsonrpc] invalid method %s" method)))))
+  (let* ((subtype (cond ((or result-supplied-p error) 'reply)
+                        (id                    'request)
+                        (method                'notification)))
+         (converted (jsonrpc-convert-to-endpoint connection args subtype))
+         (json (jsonrpc--json-encode converted))
+         (headers
+          `(("Content-Length" . ,(format "%d" (string-bytes json)))
+            ;; ("Content-Type" . "application/vscode-jsonrpc; charset=utf-8")
+            )))
     (process-send-string
      (jsonrpc--process connection)
      (cl-loop for (header . value) in headers
               concat (concat header ": " value "\r\n") into header-section
               finally return (format "%s\r\n%s" header-section json)))
-    (jsonrpc--log-event connection message 'client)))
+    (jsonrpc--log-event connection converted 'client subtype)))
 
 (defun jsonrpc-process-type (conn)
   "Return the `process-type' of JSONRPC connection CONN."
@@ -522,12 +553,13 @@ With optional CLEANUP, kill any associated buffers."
   "Encode OBJECT into a JSON string.")
 
 (cl-defun jsonrpc--reply
-    (connection id &key (result nil result-supplied-p) (error nil 
error-supplied-p))
+    (connection id method &key (result nil result-supplied-p) (error nil 
error-supplied-p))
   "Reply to CONNECTION's request ID with RESULT or ERROR."
   (apply #'jsonrpc-connection-send connection
          `(:id ,id
                ,@(and result-supplied-p `(:result ,result))
-               ,@(and error-supplied-p `(:error ,error)))))
+               ,@(and error-supplied-p `(:error ,error))
+               :method ,method)))
 
 (defun jsonrpc--call-deferred (connection)
   "Call CONNECTION's deferred actions, who may again defer themselves."
@@ -558,29 +590,15 @@ With optional CLEANUP, kill any associated buffers."
                    (jsonrpc--request-continuations connection))
         (jsonrpc--message "Server exited with status %s" (process-exit-status 
proc))
         (delete-process proc)
+        (when-let (p (slot-value connection '-autoport-inferior)) 
(delete-process p))
         (funcall (jsonrpc--on-shutdown connection) connection)))))
 
-(defvar jsonrpc--in-process-filter nil
-  "Non-nil if inside `jsonrpc--process-filter'.")
-
 (cl-defun jsonrpc--process-filter (proc string)
   "Called when new data STRING has arrived for PROC."
-  (when jsonrpc--in-process-filter
-    ;; Problematic recursive process filters may happen if
-    ;; `jsonrpc--connection-receive', called by us, eventually calls
-    ;; client code which calls `process-send-string' (which see) to,
-    ;; say send a follow-up message.  If that happens to writes enough
-    ;; bytes for pending output to be received, we will lose JSONRPC
-    ;; messages.  In that case, remove recursiveness by re-scheduling
-    ;; ourselves to run from within a timer as soon as possible
-    ;; (bug#60088)
-    (run-at-time 0 nil #'jsonrpc--process-filter proc string)
-    (cl-return-from jsonrpc--process-filter))
   (when (buffer-live-p (process-buffer proc))
     (with-current-buffer (process-buffer proc)
-      (let* ((jsonrpc--in-process-filter t)
-             (connection (process-get proc 'jsonrpc-connection))
-             (expected-bytes (jsonrpc--expected-bytes connection)))
+      (let* ((conn (process-get proc 'jsonrpc-connection))
+             (expected-bytes (jsonrpc--expected-bytes conn)))
         ;; Insert the text, advancing the process marker.
         ;;
         (save-excursion
@@ -615,24 +633,24 @@ With optional CLEANUP, kill any associated buffers."
                           expected-bytes)
                       (let* ((message-end (byte-to-position
                                            (+ (position-bytes (point))
-                                              expected-bytes))))
+                                              expected-bytes)))
+                             message
+                             )
                         (unwind-protect
                             (save-restriction
                               (narrow-to-region (point) message-end)
-                              (let* ((json-message
-                                      (condition-case-unless-debug oops
-                                          (jsonrpc--json-read)
-                                        (error
-                                         (jsonrpc--warn "Invalid JSON: %s %s"
-                                                        (cdr oops) 
(buffer-string))
-                                         nil))))
-                                (when json-message
-                                  ;; Process content in another
-                                  ;; buffer, shielding proc buffer from
-                                  ;; tamper
-                                  (with-temp-buffer
-                                    (jsonrpc-connection-receive connection
-                                                                
json-message)))))
+                              (setq message
+                                    (condition-case-unless-debug oops
+                                        (jsonrpc--json-read)
+                                      (error
+                                       (jsonrpc--warn "Invalid JSON: %s %s"
+                                                      (cdr oops) 
(buffer-string))
+                                       nil)))
+                              (when message
+                                (process-put proc 'jsonrpc-mqueue
+                                             (nconc (process-get proc
+                                                                 
'jsonrpc-mqueue)
+                                                    (list message)))))
                           (goto-char message-end)
                           (let ((inhibit-read-only t))
                             (delete-region (point-min) (point)))
@@ -641,9 +659,21 @@ With optional CLEANUP, kill any associated buffers."
                       ;; Message is still incomplete
                       ;;
                       (setq done 
:waiting-for-more-bytes-in-this-message))))))))
-          ;; Saved parsing state for next visit to this filter
+          ;; Saved parsing state for next visit to this filter, which
+          ;; may well be a recursive one stemming from the tail call
+          ;; to `jsonrpc-connection-receive' below (bug#60088).
           ;;
-          (setf (jsonrpc--expected-bytes connection) expected-bytes))))))
+          (setf (jsonrpc--expected-bytes conn) expected-bytes)
+          ;; Now, time to notify user code of one or more messages in
+          ;; order.  Very often `jsonrpc-connection-receive' will exit
+          ;; non-locally (typically the reply to a request), so do
+          ;; this all this processing in top-level loops timer.
+          (cl-loop
+           for msg = (pop (process-get proc 'jsonrpc-mqueue)) while msg
+           do (run-at-time 0 nil
+                           (lambda (m) (with-temp-buffer
+                                         (jsonrpc-connection-receive conn m)))
+                           msg)))))))
 
 (cl-defun jsonrpc--async-request-1 (connection
                                     method
@@ -737,24 +767,19 @@ TIMEOUT is nil)."
                      (apply #'format format args)
                      :warning)))
 
-(defun jsonrpc--log-event (connection message &optional type)
+(defun jsonrpc--log-event (connection message &optional origin subtype)
   "Log a JSONRPC-related event.
 CONNECTION is the current connection.  MESSAGE is a JSON-like
-plist.  TYPE is a symbol saying if this is a client or server
-originated."
+plist.  ORIGIN is a symbol saying where event originated.
+SUBTYPE tells more about the event."
   (let ((max (jsonrpc--events-buffer-scrollback-size connection)))
     (when (or (null max) (cl-plusp max))
       (with-current-buffer (jsonrpc-events-buffer connection)
-        (cl-destructuring-bind (&key method id error &allow-other-keys) message
+        (cl-destructuring-bind (&key _method id error &allow-other-keys) 
message
           (let* ((inhibit-read-only t)
-                 (subtype (cond ((and method id)       'request)
-                                (method                'notification)
-                                (id                    'reply)
-                                (t                     'message)))
                  (type
-                  (concat (format "%s" (or type 'internal))
-                          (if type
-                              (format "-%s" subtype)))))
+                  (concat (format "%s" (or origin 'internal))
+                          (if origin (format "-%s" (or subtype 'message))))))
             (goto-char (point-max))
             (prog1
                 (let ((msg (format "[%s]%s%s %s:\n%s"
@@ -776,5 +801,110 @@ originated."
                                                   (forward-line 2)
                                                   (point)))))))))))))
 
+(defun jsonrpc--forwarding-buffer (name prefix conn)
+  "Helper for `jsonrpc-process-connection' helpers.
+Make a stderr buffer named NAME, forwarding lines prefixed by
+PREFIX to CONN's events buffer."
+  (with-current-buffer (get-buffer-create name)
+    (let ((inhibit-read-only t))
+      (fundamental-mode)
+      (erase-buffer)
+      (buffer-disable-undo)
+      (add-hook
+       'after-change-functions
+       (lambda (beg _end _pre-change-len)
+         (cl-loop initially (goto-char beg)
+                  do (forward-line)
+                  when (bolp)
+                  for line = (buffer-substring
+                              (line-beginning-position 0)
+                              (line-end-position 0))
+                  do (with-current-buffer (jsonrpc-events-buffer conn)
+                       (goto-char (point-max))
+                       (let ((inhibit-read-only t))
+                         (insert (format "%s %s\n" prefix line))))
+                  until (eobp)))
+       nil t))
+    (current-buffer)))
+
+
+;;;; More convenience utils
+(cl-defun jsonrpc-autoport-bootstrap (name contact
+                                           &key connect-args)
+  "Use CONTACT to start network server, then connect to it.
+
+Return function suitable for the :PROCESS initarg of
+`jsonrpc-process-connection' (which see).
+
+CONTACT is a list where all the elements are strings except for
+one, which is usuallky the keyword `:autoport'.
+
+When the returned function is called it will start a program
+using a command based on CONTACT, where `:autoport' is
+substituted by a locally free network port.  Thereafter, a
+network is made to this port.
+
+Instead of the keyword `:autoport', a cons cell (:autoport
+FORMAT-FN) is also accepted.  In that case FORMAT-FN is passed
+the port number and should return a string used for the
+substitution.
+
+The internal processes and control buffers are named after NAME.
+
+CONNECT-ARGS are passed as additional arguments to
+`open-network-stream'."
+  (lambda (conn)
+    (let* ((port-probe (make-network-process :name "jsonrpc-port-probe-dummy"
+                                             :server t
+                                             :host "localhost"
+                                             :service 0))
+           (port-number (unwind-protect
+                            (process-contact port-probe :service)
+                          (delete-process port-probe)))
+           (inferior-buffer (jsonrpc--forwarding-buffer
+                             (format " *%s inferior output*" name)
+                             "[inferior]"
+                             conn))
+           (cmd (cl-loop for e in contact
+                         if (eq e :autoport) collect (format "%s" port-number)
+                         else if (eq (car-safe e) :autoport)
+                         collect (funcall (cdr e) port-number)
+                         else collect e))
+           inferior np)
+      (unwind-protect
+          (progn
+            (message "[jsonrpc] Attempting to start `%s'"
+                     (string-join cmd " "))
+            (setq inferior
+                  (make-process
+                   :name (format "inferior (%s)" name)
+                   :buffer inferior-buffer
+                   :noquery t
+                   :command cmd))
+            (setq np
+                  (cl-loop
+                   repeat 10 for i from 0
+                   do (accept-process-output nil 0.5)
+                   while (process-live-p inferior)
+                   do (message
+                       "[jsonrpc] %sTrying to connect to localhost:%s (attempt 
%s)"
+                       (if (zerop i) "Started.  " "")
+                       port-number (1+ i))
+                   thereis (ignore-errors
+                             (apply #'open-network-stream
+                                    (format "autostart (%s)" name)
+                                    nil
+                                    "localhost" port-number connect-args))))
+            (setf (slot-value conn '-autoport-inferior) inferior)
+            np)
+        (cond ((and (process-live-p np)
+                    (process-live-p inferior))
+               (message "[jsonrpc] Done, connected to %s!" port-number))
+              (t
+               (when inferior (delete-process inferior))
+               (when np (delete-process np))
+               (error "[jsonrpc] Could not start and/or connect")))))))
+
+
 (provide 'jsonrpc)
 ;;; jsonrpc.el ends here
diff --git a/lisp/language/hanja-util.el b/lisp/language/hanja-util.el
index b5ef9230d27..d68f8a76988 100644
--- a/lisp/language/hanja-util.el
+++ b/lisp/language/hanja-util.el
@@ -6437,7 +6437,7 @@ character.  This variable is initialized by 
`hanja-init-load'.")
     (message "")))
 
 ;; List of current conversion status.
-;; The first element is the strating position of shown list.
+;; The first element is the starting position of shown list.
 ;; It is a group number each split by `hanja-list-width'.
 ;; The second element is the position of selected element.
 ;; The third element is a list of suitable Hanja candidate.
diff --git a/lisp/language/sinhala.el b/lisp/language/sinhala.el
index bf320506001..a5c379b3aae 100644
--- a/lisp/language/sinhala.el
+++ b/lisp/language/sinhala.el
@@ -36,11 +36,11 @@
  composition-function-table
  '(#xD80 . #xDFF)
  (list (vector
-       ;; C:consonant, H:HALANT, J:ZWJ, v:vowel sign,
+       ;; C:consonant, H:HALANTA, J:ZWJ, v:vowel sign,
        ;; V:independent vowel, a:ANUSVARA .. VISARGA
        (concat
-        ;; C(HJC)*v*H?a?, or
-        
"[\u0D9A-\u0DC6]\\(?:\u0DCA\u200D[\u0D9A-\u0DC6]\\)*[\u0DCF-\u0DDF\u0DF2-\u0DF3]*\u0DCA?[\u0D82-\u0D83]?\\|"
+        ;; C(HJ|JH)C)*v*H?a?, or
+        
"[\u0D9A-\u0DC6]\\(?:\\(\u0DCA\u200D\\|\u200D\u0DCA\\)[\u0D9A-\u0DC6]\\)*[\u0DCF-\u0DDF\u0DF2-\u0DF3]*\u0DCA?[\u0D82-\u0D83]?\\|"
         ;; Va?, or
         "[\u0D85-\u0D96][\u0D82-\u0D83]?\\|"
         ;; any other singleton characters
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index f062f3bf8de..814507b3d04 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -302,7 +302,7 @@ usage: (defadvice FUNCTION (CLASS NAME [POSITION] [ARGLIST] 
FLAG...)
 (fn FUNCTION ARGS &rest BODY)" nil t)
 (function-put 'defadvice 'doc-string-elt 3)
 (function-put 'defadvice 'lisp-indent-function 2)
-(make-obsolete 'defadvice '"use advice-add or define-advice" "30.1")
+(make-obsolete 'defadvice '"use `advice-add' or `define-advice'" "30.1")
 (register-definition-prefixes "advice" '("ad-"))
 
 
@@ -1946,7 +1946,7 @@ Major mode for editing BibTeX style files.
 (register-definition-prefixes "bibtex-style" '("bibtex-style-"))
 
 
-;;; Generated autoloads from use-package/bind-key.el
+;;; Generated autoloads from bind-key.el
 
 (push (purecopy '(bind-key 2 4 1)) package--builtin-versions)
 (autoload 'bind-key "bind-key" "\
@@ -2608,7 +2608,7 @@ used instead of `browse-url-new-window-flag'.
 (fn URL &optional NEW-WINDOW)" t)
 (make-obsolete 'browse-url-w3 'nil "29.1")
 (autoload 'browse-url-w3-gnudoit "browse-url" "\
-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.
 
@@ -4668,14 +4668,14 @@ Return a string containing the `cl-prin1'-printed 
representation of OBJECT.
 (autoload 'cl-print-to-string-with-limit "cl-print" "\
 Return a string containing a printed representation of VALUE.
 Attempt to get the length of the returned string under LIMIT
-characters with appropriate settings of `print-level' and
-`print-length.'  Use PRINT-FUNCTION to print, which should take
-the arguments VALUE and STREAM and which should respect
-`print-length' and `print-level'.  LIMIT may be nil or zero in
-which case PRINT-FUNCTION will be called with `print-level' and
-`print-length' bound to nil, and it can also be t in which case
-PRINT-FUNCTION will be called with the current values of `print-level'
-and `print-length'.
+characters with appropriate settings of `print-level',
+`print-length', and `cl-print-string-length'.  Use
+PRINT-FUNCTION to print, which should take the arguments VALUE
+and STREAM and which should respect `print-length',
+`print-level', and `cl-print-string-length'.  LIMIT may be nil or
+zero in which case PRINT-FUNCTION will be called with these
+settings bound to nil, and it can also be t in which case
+PRINT-FUNCTION will be called with their current values.
 
 Use this function with `cl-prin1' to print an object,
 abbreviating it with ellipses to fit within a size limit.
@@ -4857,10 +4857,6 @@ REGEXP-GROUP is the regular expression group in REGEXP 
to use.
 ;;; Generated autoloads from emacs-lisp/comp.el
 
 (put 'no-native-compile 'safe-local-variable 'booleanp)
-(autoload 'comp-subr-trampoline-install "comp" "\
-Make SUBR-NAME effectively advice-able when called from native code.
-
-(fn SUBR-NAME)")
 (autoload 'comp-c-func-name "comp" "\
 Given NAME, return a name suitable for the native code.
 Add PREFIX in front of it.  If FIRST is not nil, pick the first
@@ -4868,42 +4864,16 @@ available name ignoring compilation context and 
potential name
 clashes.
 
 (fn NAME PREFIX &optional FIRST)")
+(autoload 'comp-trampoline-compile "comp" "\
+Synthesize compile and return a trampoline for SUBR-NAME.
+
+(fn SUBR-NAME)")
 (autoload 'comp-clean-up-stale-eln "comp" "\
 Remove all FILE*.eln* files found in `native-comp-eln-load-path'.
 The files to be removed are those produced from the original source
 filename (including FILE).
 
 (fn FILE)")
-(autoload 'native--compile-async "comp" "\
-Compile FILES asynchronously.
-FILES is one filename or a list of filenames or directories.
-
-If optional argument RECURSIVELY is non-nil, recurse into
-subdirectories of given directories.
-
-If optional argument LOAD is non-nil, request to load the file
-after compiling.
-
-The optional argument SELECTOR has the following valid values:
-
-nil -- Select all files.
-a string -- A regular expression selecting files with matching names.
-a function -- A function selecting files with matching names.
-
-The variable `native-comp-async-jobs-number' specifies the number
-of (commands) to run simultaneously.
-
-LOAD can also be the symbol `late'.  This is used internally if
-the byte code has already been loaded when this function is
-called.  It means that we request the special kind of load
-necessary in that situation, called \"late\" loading.
-
-During a \"late\" load, instead of executing all top-level forms
-of the original files, only function definitions are
-loaded (paying attention to have these effective only if the
-bytecode definition was not changed in the meantime).
-
-(fn FILES &optional RECURSIVELY LOAD SELECTOR)")
 (autoload 'comp-lookup-eln "comp" "\
 Given a Lisp source FILENAME return the corresponding .eln file if found.
 Search happens in `native-comp-eln-load-path'.
@@ -4940,9 +4910,43 @@ Force the produced .eln to be outputted in the eln system
 directory (the last entry in `native-comp-eln-load-path') unless
 `native-compile-target-directory' is non-nil.  If the environment
 variable \"NATIVE_DISABLED\" is set, only byte compile.")
-(autoload 'native-compile-async "comp" "\
+(register-definition-prefixes "comp" '("comp-" "native-comp" 
"no-native-compile"))
+
+
+;;; Generated autoloads from cedet/semantic/wisent/comp.el
+
+(register-definition-prefixes "semantic/wisent/comp" '("wisent-"))
+
+
+;;; Generated autoloads from emacs-lisp/comp-common.el
+
+(autoload 'comp-function-type-spec "comp-common" "\
+Return the type specifier of FUNCTION.
+
+This function returns a cons cell whose car is the function
+specifier, and cdr is a symbol, either `inferred' or `know'.
+If the symbol is `inferred', the type specifier is automatically
+inferred from the code itself by the native compiler; if it is
+`know', the type specifier comes from `comp-known-type-specifiers'.
+
+(fn FUNCTION)")
+(register-definition-prefixes "comp-common" '("comp-" "native-comp-"))
+
+
+;;; Generated autoloads from emacs-lisp/comp-cstr.el
+
+(register-definition-prefixes "comp-cstr" '("comp-" 
"with-comp-cstr-accessors"))
+
+
+;;; Generated autoloads from emacs-lisp/comp-run.el
+
+(autoload 'comp-subr-trampoline-install "comp-run" "\
+Make SUBR-NAME effectively advice-able when called from native code.
+
+(fn SUBR-NAME)")
+(autoload 'native--compile-async "comp-run" "\
 Compile FILES asynchronously.
-FILES is one file or a list of filenames or directories.
+FILES is one filename or a list of filenames or directories.
 
 If optional argument RECURSIVELY is non-nil, recurse into
 subdirectories of given directories.
@@ -4959,28 +4963,38 @@ a function -- A function selecting files with matching 
names.
 The variable `native-comp-async-jobs-number' specifies the number
 of (commands) to run simultaneously.
 
+LOAD can also be the symbol `late'.  This is used internally if
+the byte code has already been loaded when this function is
+called.  It means that we request the special kind of load
+necessary in that situation, called \"late\" loading.
+
+During a \"late\" load, instead of executing all top-level forms
+of the original files, only function definitions are
+loaded (paying attention to have these effective only if the
+bytecode definition was not changed in the meantime).
+
 (fn FILES &optional RECURSIVELY LOAD SELECTOR)")
-(autoload 'comp-function-type-spec "comp" "\
-Return the type specifier of FUNCTION.
+(autoload 'native-compile-async "comp-run" "\
+Compile FILES asynchronously.
+FILES is one file or a list of filenames or directories.
 
-This function returns a cons cell whose car is the function
-specifier, and cdr is a symbol, either `inferred' or `know'.
-If the symbol is `inferred', the type specifier is automatically
-inferred from the code itself by the native compiler; if it is
-`know', the type specifier comes from `comp-known-type-specifiers'.
+If optional argument RECURSIVELY is non-nil, recurse into
+subdirectories of given directories.
 
-(fn FUNCTION)")
-(register-definition-prefixes "comp" '("comp-" "make-comp-edge" "native-comp" 
"no-native-compile"))
+If optional argument LOAD is non-nil, request to load the file
+after compiling.
 
-
-;;; Generated autoloads from cedet/semantic/wisent/comp.el
+The optional argument SELECTOR has the following valid values:
 
-(register-definition-prefixes "semantic/wisent/comp" '("wisent-"))
+nil -- Select all files.
+a string -- A regular expression selecting files with matching names.
+a function -- A function selecting files with matching names.
 
-
-;;; Generated autoloads from emacs-lisp/comp-cstr.el
+The variable `native-comp-async-jobs-number' specifies the number
+of (commands) to run simultaneously.
 
-(register-definition-prefixes "comp-cstr" '("comp-" 
"with-comp-cstr-accessors"))
+(fn FILES &optional RECURSIVELY LOAD SELECTOR)")
+(register-definition-prefixes "comp-run" '("comp-" "native-comp"))
 
 
 ;;; Generated autoloads from vc/compare-w.el
@@ -5239,6 +5253,24 @@ or call the function `dynamic-completion-mode'.")
 (autoload 'dynamic-completion-mode "completion" "\
 Toggle dynamic word-completion on or off.
 
+When this minor mode is turned on, typing \\`M-RET' or \\`C-RET'
+invokes the command `complete', which completes the word or
+symbol at point using the record of words/symbols you used
+previously and the previously-inserted completions.  Typing
+a word or moving point across it constitutes \"using\" the
+word.
+
+By default, the database of all the dynamic completions that
+were inserted by \\[complete] is saved on the file specified
+by `save-completions-file-name' when you exit Emacs, and will
+be loaded from that file when this mode is enabled in a future
+Emacs session.
+
+The following important options control the various aspects of
+this mode: `enable-completion', `save-completions-flag', and
+`save-completions-retention-time'.  Few other less important
+options can be found in the `completion' group.
+
 This is a global minor mode.  If called interactively, toggle the
 `Dynamic-Completion mode' mode.  If the prefix argument is
 positive, enable the mode, and if it is zero or negative, disable
@@ -5258,6 +5290,38 @@ it is disabled.
 (register-definition-prefixes "completion" '("*c-def-regexp*" 
"*lisp-def-regexp*" "accept-completion" "add-" "cdabbrev-" 
"check-completion-length" "clear-all-completions" "cmpl-" "complet" 
"current-completion-source" "delete-completion" "enable-completion" "find-" 
"inside-locate-completion-entry" "interactive-completion-string-reader" "kill-" 
"list-all-completions" "load-completions-from-file" "make-c" "next-cdabbrev" 
"num-cmpl-sources" "reset-cdabbrev" "save" "set-c" "symbol-" "use-comp [...]
 
 
+;;; Generated autoloads from completion-preview.el
+
+(autoload 'completion-preview-mode "completion-preview" "\
+Show in-buffer completion suggestions in a preview as you type.
+
+This mode automatically shows and updates the completion preview
+according to the text around point.
+\\<completion-preview-active-mode-map>When the preview is visible, 
\\[completion-preview-insert]
+accepts the completion suggestion,
+\\[completion-preview-next-candidate] cycles forward to the next
+completion suggestion, and \\[completion-preview-prev-candidate]
+cycles backward.
+
+This is a minor mode.  If called interactively, toggle the
+`Completion-Preview mode' mode.  If the prefix argument is
+positive, enable the mode, and if it is zero or negative, disable
+the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `completion-preview-mode'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+(fn &optional ARG)" t)
+(register-definition-prefixes "completion-preview" '("completion-preview-"))
+
+
 ;;; Generated autoloads from textmodes/conf-mode.el
 
 (autoload 'conf-mode "conf-mode" "\
@@ -5569,16 +5633,8 @@ by setting them to `null'.  Note that one may undo the 
extra
 whitespace inserted by semis and braces in `auto-newline'-mode by
 consequent \\[cperl-electric-backspace].
 
-If your site has perl5 documentation in info format, you can use commands
-\\[cperl-info-on-current-command] and \\[cperl-info-on-command] to access it.
-These keys run commands `cperl-info-on-current-command' and
-`cperl-info-on-command', which one is which is controlled by variable
-`cperl-info-on-command-no-prompt' and `cperl-clobber-lisp-bindings'
-(in turn affected by `cperl-hairy').
-
-Even if you have no info-format documentation, short one-liner-style
-help is available on \\[cperl-get-help], and one can run perldoc or
-man via menu.
+Short one-liner-style help is available on \\[cperl-get-help],
+and one can run perldoc or man via menu.
 
 It is possible to show this help automatically after some idle time.
 This is regulated by variable `cperl-lazy-help-time'.  Default with
@@ -5669,7 +5725,7 @@ Run `perldoc' on WORD.
 (fn WORD)" t)
 (autoload 'cperl-perldoc-at-point "cperl-mode" "\
 Run a `perldoc' on the word around point." t)
-(register-definition-prefixes "cperl-mode" '("cperl-" "imenu-max-items"))
+(register-definition-prefixes "cperl-mode" '("cperl-"))
 
 
 ;;; Generated autoloads from progmodes/cpp.el
@@ -6249,6 +6305,13 @@ This stores EXP (without evaluating it) as the saved 
spec for SYMBOL.
 (fn &rest ARGS)")
 (autoload 'custom-save-icons "cus-edit" "\
 Save all customized icons in `custom-file'.")
+(autoload 'customize-dirlocals "cus-edit" "\
+Customize Directory Local Variables in the current directory.
+
+With optional argument FILENAME non-nil, customize the `.dir-locals.el' file
+that FILENAME specifies.
+
+(fn &optional FILENAME)" t)
 (register-definition-prefixes "cus-edit" '("Custom-" "cus" "widget-"))
 
 
@@ -6278,7 +6341,7 @@ When called from Lisp, BUFFER should be the buffer to 
use; if
 omitted, a buffer named *Custom Themes* is used.
 
 (fn &optional BUFFER)" t)
-(register-definition-prefixes "cus-theme" '("custom-" "describe-theme-1"))
+(register-definition-prefixes "cus-theme" '("custom-" "describe-theme-"))
 
 
 ;;; Generated autoloads from cedet/ede/custom.el
@@ -6632,6 +6695,13 @@ There is some minimal font-lock support (see vars
 (setq debugger 'debug)
 (autoload 'debug "debug" "\
 Enter debugger.  \\<debugger-mode-map>`\\[debugger-continue]' returns from the 
debugger.
+
+In interactive sessions, this switches to a backtrace buffer and shows
+the Lisp backtrace of function calls there.  In batch mode (more accurately,
+when `noninteractive' is non-nil), it shows the Lisp backtrace on the
+standard error stream (unless `backtrace-on-error-noninteractive' is nil),
+and then kills Emacs, causing it to exit with a negative exit code.
+
 Arguments are mainly for use when this is called from the internals
 of the evaluator.
 
@@ -7261,29 +7331,36 @@ Major mode for editing the diary file.
 
 (autoload 'dictionary-mode "dictionary" "\
 Mode for searching a dictionary.
+
 This is a mode for searching a dictionary server implementing the
 protocol defined in RFC 2229.
 
 This is a quick reference to this mode describing the default key bindings:
 \\<dictionary-mode-map>
-* \\[dictionary-close] close the dictionary buffer
-* \\[describe-mode] display this help information
-* \\[dictionary-search] ask for a new word to search
-* \\[dictionary-lookup-definition] search the word at point
-* \\[forward-button] or TAB place point to the next link
-* \\[backward-button] or S-TAB place point to the prev link
-
-* \\[dictionary-match-words] ask for a pattern and list all matching words.
-* \\[dictionary-select-dictionary] select the default dictionary
-* \\[dictionary-select-strategy] select the default search strategy
-
-* \\`RET' or \\`<mouse-2>' visit that link")
+ \\[dictionary-close]  close the dictionary buffer
+ \\[describe-mode]     display this help
+ \\[dictionary-search] ask for a new word to search
+ \\[dictionary-lookup-definition]      search for word at point
+ \\[forward-button] or \\`TAB' move point to the next link
+ \\[backward-button] or \\`S-TAB'      move point to the previous link
+
+ \\[dictionary-match-words]    ask for a pattern and list all matching words
+ \\[dictionary-select-dictionary]      select the default dictionary
+ \\[dictionary-select-strategy]        select the default search strategy
+
+ \\`RET'       visit link at point
+ \\`<mouse-2>' visit clicked link
+
+(fn)" t)
 (autoload 'dictionary "dictionary" "\
 Create a new dictionary buffer and install `dictionary-mode'." t)
 (autoload 'dictionary-search "dictionary" "\
-Search the WORD in DICTIONARY if given or in all if nil.
-It presents the selection or word at point as default input and
-allows editing it.
+Search for WORD in all the known dictionaries.
+Interactively, prompt for WORD, and offer the word at point as default.
+
+Optional argument DICTIONARY means restrict the search to only
+that one dictionary.  Interactively, with prefix argument,
+prompt for DICTIONARY.
 
 (fn WORD &optional DICTIONARY)" t)
 (autoload 'dictionary-lookup-definition "dictionary" "\
@@ -7620,7 +7697,7 @@ Like \\[dired-jump] (`dired-jump') but in other window.
 
 ;;; Generated autoloads from dired-aux.el
 
-(register-definition-prefixes "dired-aux" '("dired-"))
+(register-definition-prefixes "dired-aux" '("dired-" "shell-command-guess"))
 
 
 ;;; Generated autoloads from dired-x.el
@@ -7677,7 +7754,7 @@ If OBJECT is not already compiled, we compile it, but do 
not
 redefine OBJECT if it is a symbol.
 
 (fn OBJECT &optional BUFFER INDENT INTERACTIVE-P)" t)
-(register-definition-prefixes "disass" '("disassemble-"))
+(register-definition-prefixes "disass" '("disassemble-" "re-disassemble"))
 
 
 ;;; Generated autoloads from disp-table.el
@@ -8022,13 +8099,15 @@ Default is 2.
 
 ;;; Generated autoloads from dnd.el
 
-(defvar dnd-protocol-alist `((,(purecopy "^file:///") . dnd-open-local-file) 
(,(purecopy "^file://") . dnd-open-file) (,(purecopy "^file:") . 
dnd-open-local-file) (,(purecopy "^\\(https?\\|ftp\\|file\\|nfs\\)://") . 
dnd-open-file)) "\
+(defvar dnd-protocol-alist `((,(purecopy "^file:///") . dnd-open-local-file) 
(,(purecopy "^file://[^/]") . dnd-open-file) (,(purecopy "^file:/[^/]") . 
dnd-open-local-file) (,(purecopy "^file:[^/]") . dnd-open-local-file) 
(,(purecopy "^\\(https?\\|ftp\\|nfs\\)://") . dnd-open-file)) "\
 The functions to call for different protocols when a drop is made.
-This variable is used by `dnd-handle-one-url' and `dnd-handle-file-name'.
+This variable is used by `dnd-handle-multiple-urls'.
 The list contains of (REGEXP . FUNCTION) pairs.
 The functions shall take two arguments, URL, which is the URL dropped and
 ACTION which is the action to be performed for the drop (move, copy, link,
 private or ask).
+If a function's `dnd-multiple-handler' property is set, it is provided
+a list of each URI dropped instead.
 If no match is found here, and the value of `browse-url-browser-function'
 is a pair of (REGEXP . FUNCTION), those regexps are tried for a match.
 If no match is found, the URL is inserted as text by calling `dnd-insert-text'.
@@ -8667,7 +8746,7 @@ A second call of this function without changing point 
inserts the next match.
 A call with prefix PREFIX reads the symbol to insert from the minibuffer with
 completion.
 
-(fn PREFIX)" t)
+(fn PREFIX)" '("P"))
 (autoload 'ebrowse-tags-loop-continue "ebrowse" "\
 Repeat last operation on files in tree.
 FIRST-TIME non-nil means this is not a repetition, but the first time.
@@ -8977,7 +9056,7 @@ MERGE-AUTOSTORE-DIR is the directory in which to store 
merged files.
 (autoload 'ediff-windows-wordwise "ediff" "\
 Compare WIND-A and WIND-B, which are selected by clicking, wordwise.
 This compares the portions of text visible in each of the two windows.
-With prefix argument, DUMB-MODE, or on a non-windowing display, works as
+With prefix argument, DUMB-MODE, or on a non-graphical display, works as
 follows:
 If WIND-A is nil, use selected window.
 If WIND-B is nil, use window next to WIND-A.
@@ -8988,7 +9067,7 @@ arguments after setting up the Ediff buffers.
 (autoload 'ediff-windows-linewise "ediff" "\
 Compare WIND-A and WIND-B, which are selected by clicking, linewise.
 This compares the portions of text visible in each of the two windows.
-With prefix argument, DUMB-MODE, or on a non-windowing display, works as
+With prefix argument, DUMB-MODE, or on a non-graphical display, works as
 follows:
 If WIND-A is nil, use selected window.
 If WIND-B is nil, use window next to WIND-A.
@@ -9222,14 +9301,14 @@ Edit a keyboard macro which has been given a name by 
`name-last-kbd-macro'.
 (fn &optional PREFIX)" t)
 (autoload 'read-kbd-macro "edmacro" "\
 Read the region as a keyboard macro definition.
-The region is interpreted as spelled-out keystrokes, e.g., \"M-x abc RET\".
-See documentation for `edmacro-mode' for details.
+The region between START and END is interpreted as spelled-out keystrokes,
+e.g., \"M-x abc RET\".  See documentation for `edmacro-mode' for details.
 Leading/trailing \"C-x (\" and \"C-x )\" in the text are allowed and ignored.
 The resulting macro is installed as the \"current\" keyboard macro.
 
 In Lisp, may also be called with a single STRING argument in which case
 the result is returned rather than being installed as the current macro.
-The result will be a string if possible, otherwise an event vector.
+The result is a vector of input events.
 Second argument NEED-VECTOR means to return an event vector always.
 
 (fn START &optional END)" t)
@@ -9280,6 +9359,7 @@ Turn on EDT Emulation." t)
 ;;; Generated autoloads from progmodes/eglot.el
 
 (push (purecopy '(eglot 1 15)) package--builtin-versions)
+(define-obsolete-function-alias 'eglot-update 'eglot-upgrade-eglot "29.1")
 (autoload 'eglot "eglot" "\
 Start LSP server for PROJECT's buffers under MANAGED-MAJOR-MODES.
 
@@ -9322,12 +9402,22 @@ INTERACTIVE is ignored and provided for backward 
compatibility.
 
 (fn MANAGED-MAJOR-MODES PROJECT CLASS CONTACT LANGUAGE-IDS &optional 
INTERACTIVE)" t)
 (autoload 'eglot-ensure "eglot" "\
-Start Eglot session for current buffer if there isn't one.")
+Start Eglot session for current buffer if there isn't one.
+
+Only use this function (in major mode hooks, etc) if you are
+confident that Eglot can be started safely and efficiently for
+*every* buffer visited where these hooks may execute.
+
+Since it is difficult to establish this confidence fully, it's
+often wise to use the interactive command `eglot' instead.  This
+command only needs to be invoked once per project, as all other
+files of a given major mode visited within the same project will
+automatically become managed with no further user intervention
+needed.")
 (autoload 'eglot-upgrade-eglot "eglot" "\
 Update Eglot to latest version.
 
 (fn &rest _)" t)
-(define-obsolete-function-alias 'eglot-update 'eglot-upgrade-eglot "29.1")
 (put 'eglot-workspace-configuration 'safe-local-variable 'listp)
 (put 'eglot--debbugs-or-github-bug-uri 'bug-reference-url-format t)
 (defun eglot--debbugs-or-github-bug-uri nil (format (if (string= (match-string 
2) "github") "https://github.com/joaotavora/eglot/issues/%s"; 
"https://debbugs.gnu.org/%s";) (match-string 3)))
@@ -9455,7 +9545,7 @@ Describe CTR if it is a class constructor.
 
 ;;; Generated autoloads from emacs-lisp/eldoc.el
 
-(push (purecopy '(eldoc 1 14 0)) package--builtin-versions)
+(push (purecopy '(eldoc 1 15 0)) package--builtin-versions)
 
 
 ;;; Generated autoloads from elec-pair.el
@@ -9637,7 +9727,7 @@ displayed." t)
 
 ;;; Generated autoloads from eshell/em-basic.el
 
-(register-definition-prefixes "em-basic" '("eshell"))
+(register-definition-prefixes "em-basic" '("eshell" 
"pcomplete/eshell-mode/eshell-debug"))
 
 
 ;;; Generated autoloads from eshell/em-cmpl.el
@@ -9859,7 +9949,7 @@ Emerge two RCS revisions of a file, with another revision 
as ancestor.
  (autoload 'emoji-recent "emoji" nil t)
  (autoload 'emoji-search "emoji" nil t)
 (autoload 'emoji-list "emoji" "\
-List emojis and insert the one that's selected.
+List emojis and allow selecting and inserting one of them.
 Select the emoji by typing \\<emoji-list-mode-map>\\[emoji-list-select] on its 
picture.
 The glyph will be inserted into the buffer that was current
 when the command was invoked." t)
@@ -10296,7 +10386,7 @@ for the values of the other parameters.
 
 See `erc-tls' for the meaning of ID.
 
-(fn &key SERVER PORT NICK USER PASSWORD FULL-NAME ID)" t)
+(fn &key SERVER PORT NICK USER PASSWORD FULL-NAME ID)" '((let 
((erc--display-context `((erc-interactive-display . erc) 
,@erc--display-context))) (erc-select-read-args))))
 (defalias 'erc-select #'erc)
 (autoload 'erc-tls "erc" "\
 ERC is a powerful, modular, and extensible IRC client.
@@ -10344,7 +10434,7 @@ See Info node `(erc) Network Identifier' for details.  
Like
 CLIENT-CERTIFICATE, this parameter cannot be specified
 interactively.
 
-(fn &key SERVER PORT NICK USER PASSWORD FULL-NAME CLIENT-CERTIFICATE ID)" t)
+(fn &key SERVER PORT NICK USER PASSWORD FULL-NAME CLIENT-CERTIFICATE ID)" 
'((let ((erc-default-port erc-default-port-tls) (erc--display-context 
`((erc-interactive-display . erc-tls) ,@erc--display-context))) 
(erc-select-read-args))))
 (autoload 'erc-handle-irc-url "erc" "\
 Use ERC to IRC on HOST:PORT in CHANNEL.
 If ERC is already connected to HOST:PORT, simply /join CHANNEL.
@@ -10544,7 +10634,7 @@ server name and search for a match in 
`erc-networks-alist'.")
 
 ;;; Generated autoloads from erc/erc-truncate.el
 
-(register-definition-prefixes "erc-truncate" '("erc-max-buffer-size"))
+(register-definition-prefixes "erc-truncate" '("erc-"))
 
 
 ;;; Generated autoloads from erc/erc-xdcc.el
@@ -10560,8 +10650,8 @@ Define NAME (a symbol) as a test.
 BODY is evaluated as a `progn' when the test is run.  It should
 signal a condition on failure or just return if the test passes.
 
-`should', `should-not', `should-error' and `skip-unless' are
-useful for assertions in BODY.
+`should', `should-not', `should-error', `skip-when', and
+`skip-unless' are useful for assertions in BODY.
 
 Use `ert' to run tests interactively.
 
@@ -10576,9 +10666,7 @@ it has to be wrapped in `(eval (quote ...))'.
 If NAME is already defined as a test and Emacs is running
 in batch mode, an error is signaled.
 
-(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] [:tags \\='(TAG...)] 
BODY...)" nil t)
-(function-put 'ert-deftest 'doc-string-elt 3)
-(function-put 'ert-deftest 'lisp-indent-function 2)
+(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] [:tags \\='(TAG...)] 
BODY...)" nil 'macro)
 (autoload 'ert-run-tests-batch "ert" "\
 Run the tests specified by SELECTOR, printing results to the terminal.
 
@@ -10639,7 +10727,7 @@ This mode mainly provides some font locking.
 
 ;;; Generated autoloads from eshell/esh-cmd.el
 
-(register-definition-prefixes "esh-cmd" '("eshell" 
"pcomplete/eshell-mode/eshell-debug"))
+(register-definition-prefixes "esh-cmd" '("eshell"))
 
 
 ;;; Generated autoloads from eshell/esh-ext.el
@@ -12165,13 +12253,30 @@ Delete all settings of file-local VARIABLE from the 
-*- line.
 (autoload 'add-dir-local-variable "files-x" "\
 Add directory-local VARIABLE with its VALUE and MODE to .dir-locals.el.
 
-(fn MODE VARIABLE VALUE)" t)
+With a prefix argument, prompt for the file to modify.
+
+When called from Lisp, FILE may be the expanded name of the dir-locals file
+where to add VARIABLE.
+
+(fn MODE VARIABLE VALUE &optional FILE)" t)
 (autoload 'delete-dir-local-variable "files-x" "\
-Delete all MODE settings of file-local VARIABLE from .dir-locals.el.
+Delete all MODE settings of dir-local VARIABLE from .dir-locals.el.
 
-(fn MODE VARIABLE)" t)
+With a prefix argument, prompt for the file to modify.
+
+When called from Lisp, FILE may be the expanded name of the dir-locals file
+from where to delete VARIABLE.
+
+(fn MODE VARIABLE &optional FILE)" t)
 (autoload 'copy-file-locals-to-dir-locals "files-x" "\
-Copy file-local variables to .dir-locals.el." t)
+Copy file-local variables to .dir-locals.el.
+
+With a prefix argument, prompt for the file to modify.
+
+When called from Lisp, FILE may be the expanded name of the dir-locals file
+where to copy the file-local variables.
+
+(fn &optional FILE)" t)
 (autoload 'copy-dir-locals-to-file-locals "files-x" "\
 Copy directory-local variables to the Local Variables list." t)
 (autoload 'copy-dir-locals-to-file-locals-prop-line "files-x" "\
@@ -12259,11 +12364,17 @@ earlier in the `setq-connection-local'.  The return 
value of the
 `setq-connection-local' form is the value of the last VALUE.
 
 (fn [VARIABLE VALUE]...)" nil t)
+(autoload 'connection-local-value "files-x" "\
+Return connection-local VARIABLE for APPLICATION in `default-directory'.
+If VARIABLE does not have a connection-local binding, the value
+is the default binding of the variable.
+
+(fn VARIABLE &optional APPLICATION)" nil t)
 (autoload 'path-separator "files-x" "\
 The connection-local value of `path-separator'.")
 (autoload 'null-device "files-x" "\
 The connection-local value of `null-device'.")
-(register-definition-prefixes "files-x" '("connection-local-" 
"dir-locals-to-string" "hack-connection-local-variables" "modify-" 
"read-file-local-variable"))
+(register-definition-prefixes "files-x" '("connection-local-" 
"dir-locals-to-string" "hack-connection-local-variables" "modify-" "read-"))
 
 
 ;;; Generated autoloads from filesets.el
@@ -12685,7 +12796,7 @@ lines.
 
 ;;; Generated autoloads from progmodes/flymake.el
 
-(push (purecopy '(flymake 1 3 4)) package--builtin-versions)
+(push (purecopy '(flymake 1 3 7)) package--builtin-versions)
 (autoload 'flymake-log "flymake" "\
 Log, at level LEVEL, the message MSG formatted with ARGS.
 LEVEL is passed to `display-warning', which is used to display
@@ -12866,7 +12977,7 @@ it is disabled.
 Unconditionally turn on Flyspell mode.")
 (autoload 'turn-off-flyspell "flyspell" "\
 Unconditionally turn off Flyspell mode.")
-(autoload 'flyspell-mode-off "flyspell" "\
+(autoload 'flyspell--mode-off "flyspell" "\
 Turn Flyspell mode off.")
 (autoload 'flyspell-region "flyspell" "\
 Flyspell text between BEG and END.
@@ -15013,6 +15124,29 @@ The mode's hook is called both when the mode is 
enabled and when
 it is disabled.
 
 (fn &optional ARG)" t)
+(autoload 'lldb "gud" "\
+Run LLDB passing it COMMAND-LINE as arguments.
+If COMMAND-LINE names a program FILE to debug, LLDB will run in
+a buffer named *gud-FILE*, and the directory containing FILE
+becomes the initial working directory and source-file directory
+for the debug session.  If you don't want `default-directory' to
+change to the directory of FILE, specify FILE without leading
+directories, in which case FILE should reside either in the
+directory of the buffer from which this command is invoked, or
+it can be found by searching PATH.
+
+If COMMAND-LINE requests that LLDB attaches to a process PID, LLDB
+will run in *gud-PID*, otherwise it will run in *gud*; in these
+cases the initial working directory is the `default-directory' of
+the buffer in which this command was invoked.
+
+Please note that completion framework that complete while you
+type, like Corfu, do not work well with this mode.  You should
+consider to turn them off in this mode.
+
+This command runs functions from `lldb-mode-hook'.
+
+(fn COMMAND-LINE)" t)
 (register-definition-prefixes "gud" '("gdb-" "gud-"))
 
 
@@ -15950,7 +16084,7 @@ it is disabled.
 
 ;;; Generated autoloads from progmodes/hideshow.el
 
-(defvar hs-special-modes-alist (mapcar #'purecopy '((c-mode "{" "}" "/[*/]" 
nil nil) (c-ts-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) 
(c++-ts-mode "{" "}" "/[*/]" nil nil) (bibtex-mode ("@\\S(*\\(\\s(\\)" 1)) 
(java-mode "{" "}" "/[*/]" nil nil) (java-ts-mode "{" "}" "/[*/]" nil nil) 
(js-mode "{" "}" "/[*/]" nil) (js-ts-mode "{" "}" "/[*/]" nil) (mhtml-mode 
"{\\|<[^/>]*?" "}\\|</[^/>]*[^/]>" "<!--" mhtml-forward nil))) "\
+(defvar hs-special-modes-alist (mapcar #'purecopy '((c-mode "{" "}" "/[*/]" 
nil nil) (c-ts-mode "{" "}" "/[*/]" nil nil) (c++-mode "{" "}" "/[*/]" nil nil) 
(c++-ts-mode "{" "}" "/[*/]" nil nil) (bibtex-mode ("@\\S(*\\(\\s(\\)" 1)) 
(java-mode "{" "}" "/[*/]" nil nil) (java-ts-mode "{" "}" "/[*/]" nil nil) 
(js-mode "{" "}" "/[*/]" nil) (js-ts-mode "{" "}" "/[*/]" nil) (lua-ts-mode 
"{\\|\\[\\[" "}\\|\\]\\]" "--" nil) (mhtml-mode "{\\|<[^/>]*?" 
"}\\|</[^/>]*[^/]>" "<!--" mhtml-forward nil))) "\
 Alist for initializing the hideshow variables for different modes.
 Each element has the form
   (MODE START END COMMENT-START FORWARD-SEXP-FUNC ADJUST-BEG-FUNC
@@ -16450,8 +16584,7 @@ inlined into the compiled format versions.  This means 
that if you
 change its definition, you should explicitly call
 `ibuffer-recompile-formats'.
 
-(fn SYMBOL (&key NAME INLINE PROPS SUMMARIZER) &rest BODY)" nil t)
-(function-put 'define-ibuffer-column 'lisp-indent-function 'defun)
+(fn SYMBOL (&key NAME INLINE PROPS SUMMARIZER) &rest BODY)" nil 'macro)
 (autoload 'define-ibuffer-sorter "ibuf-macs" "\
 Define a method of sorting named NAME.
 DOCUMENTATION is the documentation of the function, which will be called
@@ -16462,9 +16595,7 @@ For sorting, the forms in BODY will be evaluated with 
`a' bound to one
 buffer object, and `b' bound to another.  BODY should return a non-nil
 value if and only if `a' is \"less than\" `b'.
 
-(fn NAME DOCUMENTATION (&key DESCRIPTION) &rest BODY)" nil t)
-(function-put 'define-ibuffer-sorter 'lisp-indent-function 1)
-(function-put 'define-ibuffer-sorter 'doc-string-elt 2)
+(fn NAME DOCUMENTATION (&key DESCRIPTION) &rest BODY)" nil 'macro)
 (autoload 'define-ibuffer-op "ibuf-macs" "\
 Generate a function which operates on a buffer.
 OP becomes the name of the function; if it doesn't begin with
@@ -16503,9 +16634,7 @@ BODY define the operation; they are forms to evaluate 
per each
 marked buffer.  BODY is evaluated with `buf' bound to the
 buffer object.
 
-(fn OP ARGS DOCUMENTATION (&key INTERACTIVE MARK MODIFIER-P DANGEROUS OPSTRING 
ACTIVE-OPSTRING BEFORE AFTER COMPLEX) &rest BODY)" nil t)
-(function-put 'define-ibuffer-op 'lisp-indent-function 2)
-(function-put 'define-ibuffer-op 'doc-string-elt 3)
+(fn OP ARGS DOCUMENTATION (&key INTERACTIVE MARK MODIFIER-P DANGEROUS OPSTRING 
ACTIVE-OPSTRING BEFORE AFTER COMPLEX) &rest BODY)" nil 'macro)
 (autoload 'define-ibuffer-filter "ibuf-macs" "\
 Define a filter named NAME.
 DOCUMENTATION is the documentation of the function.
@@ -16520,9 +16649,7 @@ not a particular buffer should be displayed or not.  
The forms in BODY
 will be evaluated with BUF bound to the buffer object, and QUALIFIER
 bound to the current value of the filter.
 
-(fn NAME DOCUMENTATION (&key READER DESCRIPTION) &rest BODY)" nil t)
-(function-put 'define-ibuffer-filter 'lisp-indent-function 2)
-(function-put 'define-ibuffer-filter 'doc-string-elt 2)
+(fn NAME DOCUMENTATION (&key READER DESCRIPTION) &rest BODY)" nil 'macro)
 (register-definition-prefixes "ibuf-macs" '("ibuffer-"))
 
 
@@ -17783,9 +17910,8 @@ it is disabled.
 
 (fn &optional ARG)" t)
 (autoload 'image-mode-to-text "image-mode" "\
-Set a non-image mode as major mode in combination with image minor mode.
-A non-mage major mode found from `auto-mode-alist' or fundamental mode
-displays an image file as text.")
+Set current buffer's modes be a non-image major mode, plus `image-minor-mode'.
+A non-image major mode displays an image file as text.")
 (autoload 'image-bookmark-jump "image-mode" "\
 
 
@@ -17963,6 +18089,42 @@ Convert old Emacs Devanagari characters to UCS.
 (register-definition-prefixes "ind-util" '("combinatorial" "indian-" 
"is13194-"))
 
 
+;;; Generated autoloads from indent-aux.el
+
+(defvar kill-ring-deindent-mode nil "\
+Non-nil if Kill-Ring-Deindent mode is enabled.
+See the `kill-ring-deindent-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `kill-ring-deindent-mode'.")
+(custom-autoload 'kill-ring-deindent-mode "indent-aux" nil)
+(autoload 'kill-ring-deindent-mode "indent-aux" "\
+Toggle removal of indentation from text saved to the kill ring.
+
+When this minor mode is enabled, text saved into the kill ring is
+indented towards the left by the column number at the start of
+that text.
+
+This is a global minor mode.  If called interactively, toggle the
+`Kill-Ring-Deindent mode' mode.  If the prefix argument is
+positive, enable the mode, and if it is zero or negative, disable
+the mode.
+
+If called from Lisp, toggle the mode if ARG is `toggle'.  Enable
+the mode if ARG is nil, omitted, or is a positive number.
+Disable the mode if ARG is a negative number.
+
+To check whether the minor mode is enabled in the current buffer,
+evaluate `(default-value \\='kill-ring-deindent-mode)'.
+
+The mode's hook is called both when the mode is enabled and when
+it is disabled.
+
+(fn &optional ARG)" t)
+(register-definition-prefixes "indent-aux" 
'("kill-ring-deindent-buffer-substring-function"))
+
+
 ;;; Generated autoloads from leim/quail/indian.el
 
 (register-definition-prefixes "quail/indian" '("indian-mlm-mozhi-u" 
"inscript-" "quail-" "tamil"))
@@ -18610,6 +18772,8 @@ If APPEND is non-nil, don't erase previous debugging 
output.
 (fn &optional APPEND)" t)
 (autoload 'ispell-continue "ispell" "\
 Continue a halted spelling session beginning with the current word." t)
+(autoload 'ispell-completion-at-point "ispell" "\
+Word completion function for use in `completion-at-point-functions'.")
 (autoload 'ispell-complete-word "ispell" "\
 Try to complete the word before or at point.
 If optional INTERIOR-FRAG is non-nil, then the word may be a character
@@ -18866,7 +19030,7 @@ Major mode for editing JSON, powered by tree-sitter.
 
 ;;; Generated autoloads from jsonrpc.el
 
-(push (purecopy '(jsonrpc 1 0 17)) package--builtin-versions)
+(push (purecopy '(jsonrpc 1 0 18)) package--builtin-versions)
 (register-definition-prefixes "jsonrpc" '("jsonrpc-"))
 
 
@@ -19267,6 +19431,13 @@ the variables of the outer one.  You can, however, 
access alists
 inside the original alist by using dots inside the symbol, as
 displayed in the example above.
 
+Note that there is no way to differentiate the case where a key
+is missing from when it is present, but its value is nil.  Thus,
+the following form evaluates to nil:
+
+    (let-alist \\='((some-key . nil))
+      .some-key)
+
 (fn ALIST &rest BODY)" nil t)
 (function-put 'let-alist 'lisp-indent-function 1)
 (register-definition-prefixes "let-alist" '("let-alist--"))
@@ -19315,6 +19486,7 @@ sleep in seconds.
 
 ;;; Generated autoloads from emacs-lisp/loaddefs-gen.el
 
+(put 'autoload-compute-prefixes 'safe-local-variable #'booleanp)
 (put 'generated-autoload-file 'safe-local-variable 'stringp)
 (put 'generated-autoload-load-name 'safe-local-variable 'stringp)
 (autoload 'loaddefs-generate "loaddefs-gen" "\
@@ -19380,7 +19552,7 @@ remove symbols from it in the event that the package 
has done
 something strange, such as redefining an Emacs function.
 
 (fn FEATURE &optional FORCE)" t)
-(register-definition-prefixes "loadhist" '("feature-" "file-" "loadhist-" 
"read-feature" "unload-"))
+(register-definition-prefixes "loadhist" '("feature-" "file-" 
"loadhist-unload-filename" "read-feature" "unload-"))
 
 
 ;;; Generated autoloads from cedet/ede/locate.el
@@ -19570,6 +19742,19 @@ Otherwise they are treated as Emacs regexps (for 
backward compatibility).")
 (register-definition-prefixes "ls-lisp" '("ls-lisp-"))
 
 
+;;; Generated autoloads from progmodes/lua-ts-mode.el
+
+(autoload 'lua-ts-inferior-lua "lua-ts-mode" "\
+Run a Lua interpreter in an inferior process." t)
+(autoload 'lua-ts-mode "lua-ts-mode" "\
+Major mode for editing Lua files, powered by tree-sitter.
+
+\\{lua-ts-mode-map}
+
+(fn)" t)
+(register-definition-prefixes "lua-ts-mode" '("lua-ts-"))
+
+
 ;;; Generated autoloads from calendar/lunar.el
 
 (autoload 'lunar-phases "lunar" "\
@@ -19993,15 +20178,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'.
@@ -20019,24 +20197,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
@@ -20052,10 +20212,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 `.'.
@@ -20139,6 +20295,11 @@ Note that in some cases you will need to use 
\\[quoted-insert] to quote the
 SPC character in the above examples, because this command attempts
 to auto-complete your input based on the installed manual pages.
 
+If `default-directory' is remote, and `Man-support-remote-systems'
+is non-nil, this command formats the man page on the remote system.
+A prefix argument reverses the value of `Man-support-remote-systems'
+for the current invocation.
+
 (fn MAN-ARGS)" t)
 (autoload 'man-follow "man" "\
 Get a Un*x manual page of the item under point and put it in a buffer.
@@ -20357,7 +20518,15 @@ for \"x-scheme-handler/mailto;\" to \"emacs -f 
message-mailto %u\"
 will then start up Emacs ready to compose mail.  For emacsclient use
   emacsclient -e \\='(message-mailto \"%u\")'
 
-(fn &optional URL)" t)
+To facilitate the use of this function within window systems that
+provide message subject, body and attachments independent of URL
+itself, the arguments SUBJECT, BODY and FILE-ATTACHMENTS may also
+provide alternative message subject and body text, which is
+inserted in lieu of nothing if URL does not incorporate such
+information itself, and a list of files to insert as attachments
+to the E-mail.
+
+(fn &optional URL SUBJECT BODY FILE-ATTACHMENTS)" t)
 (register-definition-prefixes "message" '("message-"))
 
 
@@ -20897,7 +21066,21 @@ With a prefix argument, ask for a wildcard, and search 
in file buffers
 whose file names match the specified wildcard.
 
 (fn FILES)" t)
-(register-definition-prefixes "misearch" '("misearch-unload-function" 
"multi-isearch-"))
+(autoload 'multi-file-replace-regexp-as-diff "misearch" "\
+Show as diffs replacements of REGEXP with TO-STRING in FILES.
+DELIMITED has the same meaning as in `replace-regexp'.
+The replacements are displayed in the buffer *replace-diff* that
+you can later apply as a patch after reviewing the changes.
+
+(fn FILES REGEXP TO-STRING &optional DELIMITED)" t)
+(autoload 'replace-regexp-as-diff "misearch" "\
+Show as diffs replacements of REGEXP with TO-STRING in the current buffer.
+DELIMITED has the same meaning as in `replace-regexp'.
+The replacements are displayed in the buffer *replace-diff* that
+you can later apply as a patch after reviewing the changes.
+
+(fn REGEXP TO-STRING &optional DELIMITED)" t)
+(register-definition-prefixes "misearch" '("misearch-unload-function" 
"multi-"))
 
 
 ;;; Generated autoloads from progmodes/mixal-mode.el
@@ -22561,7 +22744,7 @@ Coloring:
 
 ;;; Generated autoloads from org/org.el
 
-(push (purecopy '(org 9 6 7)) package--builtin-versions)
+(push (purecopy '(org 9 6 11)) package--builtin-versions)
 (autoload 'org-babel-do-load-languages "org" "\
 Load the languages defined in `org-babel-load-languages'.
 
@@ -23527,8 +23710,7 @@ that code in the early init-file.
 (fn &optional NO-ACTIVATE)" t)
 (defun package-activate-all nil "\
 Activate all installed packages.
-The variable `package-load-list' controls which packages to load." (setq 
package--activated t) (let* ((elc (concat package-quickstart-file "c")) (qs (if 
(file-readable-p elc) elc (if (file-readable-p package-quickstart-file) 
package-quickstart-file)))) (if (and qs (not (bound-and-true-p 
package-activated-list))) (let ((load-source-file-function nil)) (unless 
(boundp 'package-activated-list) (setq package-activated-list nil)) (load qs 
nil 'nomessage)) (require 'package) (package--activate [...]
-(autoload 'package--activate-all "package")
+The variable `package-load-list' controls which packages to load." (setq 
package--activated t) (let* ((elc (concat package-quickstart-file "c")) (qs (if 
(file-readable-p elc) elc (if (file-readable-p package-quickstart-file) 
package-quickstart-file)))) (or (and qs (not (bound-and-true-p 
package-activated-list)) (with-demoted-errors "Error during quickstart: %S" 
(let ((load-source-file-function nil)) (unless (boundp 'package-activated-list) 
(setq package-activated-list nil)) (load qs nil  [...]
 (autoload 'package-import-keyring "package" "\
 Import keys from FILE.
 
@@ -23670,40 +23852,59 @@ DESC must be a `package-desc' object.
 (autoload 'package-vc-install-selected-packages "package-vc" "\
 Ensure packages specified in `package-vc-selected-packages' are installed." t)
 (autoload 'package-vc-upgrade-all "package-vc" "\
-Attempt to upgrade all installed VC packages." t)
+Upgrade all installed VC packages.
+
+This may fail if the local VCS state of one of the packages
+conflicts with its remote repository state." t)
 (autoload 'package-vc-upgrade "package-vc" "\
-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.
 
 (fn PKG-DESC)" t)
 (autoload 'package-vc-install "package-vc" "\
-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)" t)
+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.
+
+(fn PACKAGE &optional REV BACKEND NAME)" t)
 (autoload 'package-vc-checkout "package-vc" "\
 Clone the sources for PKG-DESC into DIRECTORY and visit that directory.
 Unlike `package-vc-install', this does not yet set up the package
@@ -23717,14 +23918,14 @@ for the last released version of the package.
 
 (fn PKG-DESC DIRECTORY &optional REV)" t)
 (autoload 'package-vc-install-from-checkout "package-vc" "\
-Set up the package NAME in DIR by linking it into the ELPA directory.
+Install the package NAME from its source directory DIR.
+NAME defaults to the base name of 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
-for the NAME of the package to set up.  Otherwise infer the package
-name from the base name of DIR.
+for the NAME of the package to set up.
 
-(fn DIR NAME)" t)
+(fn DIR &optional NAME)" t)
 (autoload 'package-vc-rebuild "package-vc" "\
 Rebuild the installation for package given by PKG-DESC.
 Rebuilding an installation means scraping for new autoload
@@ -23736,14 +23937,18 @@ prompt for the name of the package to rebuild.
 
 (fn PKG-DESC)" t)
 (autoload 'package-vc-prepare-patch "package-vc" "\
-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.
 
+See also `vc-prepare-patch'.
+
 (fn PKG-DESC SUBJECT REVISIONS)" t)
 (register-definition-prefixes "package-vc" '("package-vc-"))
 
@@ -23772,6 +23977,11 @@ archive).
 (register-definition-prefixes "page-ext" '("pages-"))
 
 
+;;; Generated autoloads from leim/quail/pakistan.el
+
+(register-definition-prefixes "quail/pakistan" '("pakistan-"))
+
+
 ;;; Generated autoloads from calendar/parse-time.el
 
 (put 'parse-time-rules 'risky-local-variable t)
@@ -24105,7 +24315,7 @@ Completion for checksum commands.")
 (defalias 'pcomplete/sha224sum 'pcomplete/md5sum)
 (defalias 'pcomplete/sha256sum 'pcomplete/md5sum)
 (defalias 'pcomplete/sha384sum 'pcomplete/md5sum)
-(defalias 'pcomplete/sha521sum 'pcomplete/md5sum)
+(defalias 'pcomplete/sha512sum 'pcomplete/md5sum)
 (autoload 'pcomplete/sort "pcmpl-unix" "\
 Completion for the `sort' command.")
 (autoload 'pcomplete/shuf "pcmpl-unix" "\
@@ -24234,6 +24444,8 @@ Includes files as well as host names followed by a 
colon.")
 (autoload 'pcomplete/telnet "pcmpl-unix")
 (autoload 'pcomplete/sudo "pcmpl-unix" "\
 Completion for the `sudo' command.")
+(autoload 'pcomplete/doas "pcmpl-unix" "\
+Completion for the `doas' command.")
 (register-definition-prefixes "pcmpl-unix" '("pcmpl-" "pcomplete/"))
 
 
@@ -24542,6 +24754,11 @@ they are not by default assigned to keys." t)
 (register-definition-prefixes "picture" '("picture-"))
 
 
+;;; Generated autoloads from language/pinyin.el
+
+(register-definition-prefixes "pinyin" '("pinyin-character-map"))
+
+
 ;;; Generated autoloads from textmodes/pixel-fill.el
 
 (register-definition-prefixes "pixel-fill" '("pixel-fill-"))
@@ -24598,7 +24815,7 @@ or call the function `pixel-scroll-precision-mode'.")
 (autoload 'pixel-scroll-precision-mode "pixel-scroll" "\
 Toggle pixel scrolling.
 
-When enabled, this minor mode allows to scroll the display
+When enabled, this minor mode allows you to scroll the display
 precisely, according to the turning of the mouse wheel.
 
 This is a global minor mode.  If called interactively, toggle the
@@ -25314,7 +25531,7 @@ Open profile FILENAME.
 
 ;;; Generated autoloads from progmodes/project.el
 
-(push (purecopy '(project 0 9 8)) package--builtin-versions)
+(push (purecopy '(project 0 10 0)) package--builtin-versions)
 (autoload 'project-current "project" "\
 Return the project instance in DIRECTORY, defaulting to `default-directory'.
 
@@ -25335,12 +25552,12 @@ See the doc string of `project-find-functions' for 
the general form
 of the project instance object.
 
 (fn &optional MAYBE-PROMPT DIRECTORY)")
-(put 'project-vc-ignores 'safe-local-variable #'listp)
+(put 'project-vc-ignores 'safe-local-variable (lambda (val) (and (listp val) 
(not (memq nil (mapcar #'stringp val))))))
 (put 'project-vc-merge-submodules 'safe-local-variable #'booleanp)
 (put 'project-vc-include-untracked 'safe-local-variable #'booleanp)
 (put 'project-vc-name 'safe-local-variable #'stringp)
 (put 'project-vc-extra-root-markers 'safe-local-variable (lambda (val) (and 
(listp val) (not (memq nil (mapcar #'stringp val))))))
-(defvar project-prefix-map (let ((map (make-sparse-keymap))) (define-key map 
"!" 'project-shell-command) (define-key map "&" 'project-async-shell-command) 
(define-key map "f" 'project-find-file) (define-key map "F" 
'project-or-external-find-file) (define-key map "b" 'project-switch-to-buffer) 
(define-key map "s" 'project-shell) (define-key map "d" 'project-find-dir) 
(define-key map "D" 'project-dired) (define-key map "v" 'project-vc-dir) 
(define-key map "c" 'project-compile) (define-key  [...]
+(defvar project-prefix-map (let ((map (make-sparse-keymap))) (define-key map 
"!" 'project-shell-command) (define-key map "&" 'project-async-shell-command) 
(define-key map "f" 'project-find-file) (define-key map "F" 
'project-or-external-find-file) (define-key map "b" 'project-switch-to-buffer) 
(define-key map "s" 'project-shell) (define-key map "d" 'project-find-dir) 
(define-key map "D" 'project-dired) (define-key map "v" 'project-vc-dir) 
(define-key map "c" 'project-compile) (define-key  [...]
 Keymap for project commands.")
  (define-key ctl-x-map "p" project-prefix-map)
 (autoload 'project-other-window-command "project" "\
@@ -25386,7 +25603,8 @@ pattern to search for.
 Visit a file (with completion) in the current project.
 
 The filename at point (determined by `thing-at-point'), if any,
-is available as part of \"future history\".
+is available as part of \"future history\".  If none, the current
+buffer's file name is used.
 
 If INCLUDE-ALL is non-nil, or with prefix argument when called
 interactively, include all files under the project root, except
@@ -25397,7 +25615,8 @@ for VCS directories listed in 
`vc-directory-exclusion-list'.
 Visit a file (with completion) in the current project or external roots.
 
 The filename at point (determined by `thing-at-point'), if any,
-is available as part of \"future history\".
+is available as part of \"future history\".  If none, the current
+buffer's file name is used.
 
 If INCLUDE-ALL is non-nil, or with prefix argument when called
 interactively, include all files under the project root, except
@@ -25405,7 +25624,10 @@ for VCS directories listed in 
`vc-directory-exclusion-list'.
 
 (fn &optional INCLUDE-ALL)" t)
 (autoload 'project-find-dir "project" "\
-Start Dired in a directory inside the current project." t)
+Start Dired in a directory inside the current project.
+
+The current buffer's `default-directory' is available as part of
+\"future history\"." t)
 (autoload 'project-dired "project" "\
 Start Dired in the current project's root." t)
 (autoload 'project-vc-dir "project" "\
@@ -25520,6 +25742,24 @@ Return the list of root directories of all known 
projects.")
 (autoload 'project-execute-extended-command "project" "\
 Execute an extended command in project root." t)
 (function-put 'project-execute-extended-command 'interactive-only 
'command-execute)
+(autoload 'project-any-command "project" "\
+Run the next command in the current project.
+
+If the command name starts with `project-', or its symbol has
+property `project-related', it gets passed the project to use
+with the variable `project-current-directory-override'.
+Otherwise, `default-directory' is temporarily set to the current
+project's root.
+
+If OVERRIDING-MAP is non-nil, it will be used as
+`overriding-local-map' to provide shorter bindings from that map
+which will take priority over the global ones.
+
+(fn &optional OVERRIDING-MAP PROMPT-FORMAT)" t)
+(autoload 'project-prefix-or-any-command "project" "\
+Run the next command in the current project.
+Works like `project-any-command', but also mixes in the shorter
+bindings from `project-prefix-map'." t)
 (autoload 'project-switch-project "project" "\
 \"Switch\" to another project by running an Emacs command.
 The available commands are presented as a dispatch menu
@@ -25538,6 +25778,12 @@ the buffer's directory name when buffers from two 
different projects
 would otherwise have the same name.
 
 (fn DIRNAME)")
+(defvar project-mode-line nil "\
+Whether to show current project name and Project menu on the mode line.
+This feature requires the presence of the following item in
+`mode-line-format': `(project-mode-line project-mode-line-format)'; it
+is part of the default mode line beginning with Emacs 30.")
+(custom-autoload 'project-mode-line "project" t)
 (register-definition-prefixes "project" '("project-"))
 
 
@@ -26576,7 +26822,7 @@ This enforces rescanning the buffer on next use.")
 (put 'reftex-vref-is-default 'safe-local-variable (lambda (x) (or (stringp x) 
(symbolp x))))
 (put 'reftex-fref-is-default 'safe-local-variable (lambda (x) (or (stringp x) 
(symbolp x))))
 (put 'reftex-level-indent 'safe-local-variable 'integerp)
-(put 'reftex-guess-label-type 'safe-local-variable (lambda (x) (memq x '(nil 
t))))
+(put 'reftex-guess-label-type 'safe-local-variable #'booleanp)
 (register-definition-prefixes "reftex-vars" '("reftex-"))
 
 
@@ -28439,7 +28685,7 @@ Like `mail' command, but display mail buffer in another 
frame.
 
 ;;; Generated autoloads from emacs-lisp/seq.el
 
-(push (purecopy '(seq 2 23)) package--builtin-versions)
+(push (purecopy '(seq 2 24)) package--builtin-versions)
 
 
 ;;; Generated autoloads from server.el
@@ -30475,6 +30721,8 @@ but with the twist that BODY can evaluate itself 
recursively by
 calling NAME, where the arguments passed to NAME are used
 as the new values of the bound variables in the recursive invocation.
 
+This construct can only be used with lexical binding.
+
 (fn NAME BINDINGS &rest BODY)" nil t)
 (function-put 'named-let 'lisp-indent-function 2)
 (autoload 'string-pixel-width "subr-x" "\
@@ -32306,7 +32554,10 @@ Convert SECONDS to a proper time, like `current-time' 
would.
 
 (fn SECONDS)")
 (autoload 'days-to-time "time-date" "\
-Convert DAYS into a time value.
+Convert Emacs-epoch DAYS into a time value.
+Note that this does not use the same epoch as `time-to-days'; you
+must subtract (time-to-days 0) first to convert, and may get nil
+if the result is before the start.
 
 (fn DAYS)")
 (autoload 'time-since "time-date" "\
@@ -32335,7 +32586,7 @@ Return the day number within the year corresponding to 
TIME.
 
 (fn TIME)")
 (autoload 'time-to-days "time-date" "\
-The absolute date corresponding to TIME, a time value.
+The absolute pseudo-Gregorian date for TIME, a time value.
 The absolute date is the number of days elapsed since the imaginary
 Gregorian date Sunday, December 31, 1 BC.
 
@@ -32652,20 +32903,14 @@ and done items are always shown on visiting a 
category.
 (autoload 'todo-mode "todo-mode" "\
 Major mode for displaying, navigating and editing todo lists.
 
-\\{todo-mode-map}
-
 (fn)" t)
 (autoload 'todo-archive-mode "todo-mode" "\
 Major mode for archived todo categories.
 
-\\{todo-archive-mode-map}
-
 (fn)" t)
 (autoload 'todo-filtered-items-mode "todo-mode" "\
 Mode for displaying and reprioritizing top priority Todo.
 
-\\{todo-filtered-items-mode-map}
-
 (fn)" t)
 (register-definition-prefixes "todo-mode" '("todo-"))
 
@@ -32966,6 +33211,7 @@ Add archive file name handler to 
`file-name-handler-alist'." (when (and tramp-ar
 
 ;;; Generated autoloads from transient.el
 
+(push (purecopy '(transient 0 5 2)) package--builtin-versions)
 (autoload 'transient-define-prefix "transient" "\
 Define NAME as a transient prefix command.
 
@@ -33058,7 +33304,7 @@ See info node `(transient)Modifying Existing 
Transients'.
 
 (fn PREFIX LOC)")
 (function-put 'transient-remove-suffix 'lisp-indent-function 'defun)
-(register-definition-prefixes "transient" '("transient"))
+(register-definition-prefixes "transient" '("static-if" "transient"))
 
 
 ;;; Generated autoloads from tree-widget.el
@@ -33307,7 +33553,9 @@ FRAC should be the inverse of the fractional value; for 
example, a value of
 ;;; Generated autoloads from progmodes/typescript-ts-mode.el
 
 (autoload 'typescript-ts-base-mode "typescript-ts-mode" "\
-Major mode for editing TypeScript.
+Generic major mode for editing TypeScript.
+
+This mode is intended to be inherited by concrete major modes.
 
 (fn)" t)
 (autoload 'typescript-ts-mode "typescript-ts-mode" "\
@@ -33326,7 +33574,7 @@ The JSX-specific faces are used when 
`treesit-font-lock-level' is
 at least 3 (which is the default value).
 
 (fn)" t)
-(register-definition-prefixes "typescript-ts-mode" '("tsx-ts-mode--" 
"typescript-ts-mode-"))
+(register-definition-prefixes "typescript-ts-mode" '("tsx-ts-" 
"typescript-ts-"))
 
 
 ;;; Generated autoloads from international/ucs-normalize.el
@@ -33610,6 +33858,7 @@ Handle file: and ftp: URLs.
 Attempt to resolve the given HOST using nslookup if possible.
 
 (fn HOST)" t)
+(make-obsolete 'url-gateway-nslookup-host 'nil "30.1")
 (autoload 'url-open-stream "url-gw" "\
 Open a stream to HOST, possibly via a gateway.
 Args per `open-network-stream'.
@@ -34377,18 +34626,23 @@ responsible for the given file.
 (autoload 'vc-next-action "vc" "\
 Do the next logical version control operation on the current fileset.
 This requires that all files in the current VC fileset be in the
-same state.  If not, signal an error.
-
-For merging-based version control systems:
-  If every file in the VC fileset is not registered for version
-   control, register the fileset (but don't commit).
-  If every work file in the VC fileset is added or changed, pop
-   up a *vc-log* buffer to commit the fileset.
+same state.  If they are not, signal an error.  Also signal an error if
+files in the fileset are missing (removed, but tracked by version control),
+or are ignored by the version control system.
+
+For modern merging-based version control systems:
+  If every file in the fileset is not registered for version
+   control, register the fileset (but don't commit).  If VERBOSE is
+   non-nil (interactively, the prefix argument), ask for the VC
+   backend with which to register the fileset.
+  If every work file in the VC fileset is either added or modified,
+   pop up a *vc-log* buffer to commit the fileset changes.
   For a centralized version control system, if any work file in
    the VC fileset is out of date, offer to update the fileset.
 
 For old-style locking-based version control systems, like RCS:
-  If every file is not registered, register the file(s).
+  If every file is not registered, register the file(s); with a prefix
+   argument, allow to specify the VC backend for registration.
   If every file is registered and unlocked, check out (lock)
    the file(s) for editing.
   If every file is locked by you and has changes, pop up a
@@ -34396,14 +34650,21 @@ For old-style locking-based version control systems, 
like RCS:
    read-only copy of each changed file after checking in.
   If every file is locked by you and unchanged, unlock them.
   If every file is locked by someone else, offer to steal the lock.
+  If files are unlocked, but have changes, offer to either claim the
+   lock or revert to the last checked-in version.
+
+If this command is invoked from a patch buffer under `diff-mode', it
+will apply the diffs from the patch and pop up a *vc-log* buffer to
+check-in the resulting changes.
 
 When using this command to register a new file (or files), it
 will automatically deduce which VC repository to register it
 with, using the most specific one.
 
 If VERBOSE is non-nil (interactively, the prefix argument),
-you can specify a VC backend or (for centralized VCS only)
-the revision ID or branch ID.
+you can specify another VC backend for the file(s),
+or (for centralized VCS only) the revision ID or branch ID
+from which to check out the file(s).
 
 (fn VERBOSE)" t)
 (autoload 'vc-register "vc" "\
@@ -34707,7 +34968,7 @@ On a non-distributed version control system, this 
signals an error.
 It also signals an error in a Bazaar bound branch.
 
 (fn &optional ARG)" t)
-(autoload 'vc-switch-backend "vc" "\
+(autoload 'vc-change-backend "vc" "\
 Make BACKEND the current version control system for FILE.
 FILE must already be registered in BACKEND.  The change is not
 permanent, only for the current session.  This function only changes
@@ -34716,7 +34977,6 @@ By default, this command cycles through the registered 
backends.
 To get a prompt, use a prefix argument.
 
 (fn FILE BACKEND)" t)
-(make-obsolete 'vc-switch-backend 'nil "28.1")
 (autoload 'vc-transfer-file "vc" "\
 Transfer FILE to another version control system NEW-BACKEND.
 If NEW-BACKEND has a higher precedence than FILE's current backend
@@ -36107,6 +36367,18 @@ so the value of `wallpaper-commands' is ignored.
 
 ;;; Generated autoloads from emacs-lisp/warnings.el
 
+(defvar warning-suppress-types nil "\
+List of warning types not to display immediately.
+If any element of this list matches the TYPE argument to `display-warning',
+the warning is logged nonetheless, but the warnings buffer is
+not immediately displayed.
+The element must match an initial segment of the list TYPE.
+Thus, (foo bar) as an element matches (foo bar)
+or (foo bar ANYTHING...) as TYPE.
+If TYPE is a symbol FOO, that is equivalent to the list (FOO),
+so only the element (FOO) will match it.
+See also `warning-suppress-log-types'.")
+(custom-autoload 'warning-suppress-types "warnings" t)
 (defvar warning-prefix-function nil "\
 Function to generate warning prefixes.
 This function, if non-nil, is called with two arguments,
@@ -36971,6 +37243,10 @@ updated (e.g. to re-interpret the current directory).
 Used non-interactively, arguments are optional: if given then TOPIC
 should be a topic string and non-nil RE-CACHE forces re-caching.
 
+Note that `M-x woman' doesn’t yet support the latest features of
+modern man pages, so we recommend using `M-x man' if that is
+available on your system.
+
 (fn &optional TOPIC RE-CACHE)" t)
 (autoload 'woman-dired-find-file "woman" "\
 In dired, run the WoMan man-page browser on this file." t)
@@ -37355,6 +37631,101 @@ run a specific program.  The program must be a member 
of
 
 (fn &optional PGM)" t)
 (register-definition-prefixes "zone" '("zone-"))
+
+
+;;; Generated autoloads from emacs-lisp/ert-font-lock.el
+
+(autoload 'ert-font-lock-deftest "ert-font-lock" "\
+Define test NAME (a symbol) using assertions from TEST-STR.
+
+Other than MAJOR-MODE and TEST-STR parameters, this macro accepts
+the same parameters and keywords as `ert-deftest' and is intended
+to be used through `ert'.
+
+(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] [:tags \\='(TAG...)] 
MAJOR-MODE TEST-STR)" nil t)
+(function-put 'ert-font-lock-deftest 'doc-string-elt 3)
+(function-put 'ert-font-lock-deftest 'lisp-indent-function 2)
+(autoload 'ert-font-lock-deftest-file "ert-font-lock" "\
+Define test NAME (a symbol) using assertions from FILE.
+
+FILE - path to a file with assertions in ERT resource director as
+return by `ert-resource-directory'.
+
+Other than MAJOR-MODE and FILE parameters, this macro accepts the
+same parameters and keywords as `ert-deftest' and is intended to
+be used through `ert'.
+
+(fn NAME () [DOCSTRING] [:expected-result RESULT-TYPE] [:tags \\='(TAG...)] 
MAJOR-MODE FILE)" nil t)
+(function-put 'ert-font-lock-deftest-file 'doc-string-elt 3)
+(function-put 'ert-font-lock-deftest-file 'lisp-indent-function 2)
+(autoload 'ert-font-lock-test-string "ert-font-lock" "\
+Check font faces in TEST-STRING set by MODE.
+
+The function is meant to be run from within an ERT test.
+
+(fn TEST-STRING MODE)")
+(autoload 'ert-font-lock-test-file "ert-font-lock" "\
+Check font faces in FILENAME set by MODE.
+
+The function is meant to be run from within an ERT test.
+
+(fn FILENAME MODE)")
+(register-definition-prefixes "ert-font-lock" '("ert-font-lock--"))
+
+
+;;; Generated autoloads from touch-screen.el
+
+(autoload 'touch-screen-hold "touch-screen" "\
+Handle a long press EVENT.
+Ding and select the window at EVENT, then activate the mark.  If
+`touch-screen-word-select' is enabled, try to select the whole
+word around EVENT; otherwise, set point to the location of EVENT.
+
+(fn EVENT)" t)
+(autoload 'touch-screen-track-tap "touch-screen" "\
+Track a single tap starting from EVENT.
+EVENT should be a `touchscreen-begin' event.
+
+Read touch screen events until a `touchscreen-end' event is
+received with the same ID as in EVENT.  If UPDATE is non-nil and
+a `touchscreen-update' event is received in the mean time and
+contains a touch point with the same ID as in EVENT, call UPDATE
+with that event and DATA.
+
+If THRESHOLD is non-nil, enforce a threshold of movement that is
+either itself or 10 pixels when it is not a number.  If the
+aformentioned touch point moves beyond that threshold on any
+axis, return nil immediately, and further resume mouse event
+translation for the touch point at hand.
+
+Return nil immediately if any other kind of event is received;
+otherwise, return t once the `touchscreen-end' event arrives.
+
+(fn EVENT &optional UPDATE DATA THRESHOLD)")
+(autoload 'touch-screen-track-drag "touch-screen" "\
+Track a single drag starting from EVENT.
+EVENT should be a `touchscreen-begin' event.
+
+Read touch screen events until a `touchscreen-end' event is
+received with the same ID as in EVENT.  For each
+`touchscreen-update' event received in the mean time containing a
+touch point with the same ID as in EVENT, call UPDATE with the
+touch point in event and DATA, once the touch point has moved
+significantly by at least 5 pixels from where it was in EVENT.
+
+Return nil immediately if any other kind of event is received;
+otherwise, return either t or `no-drag' once the
+`touchscreen-end' event arrives; return `no-drag' returned if the
+touch point in EVENT did not move significantly, and t otherwise.
+
+(fn EVENT UPDATE &optional DATA)")
+(autoload 'touch-screen-inhibit-drag "touch-screen" "\
+Inhibit subsequent `touchscreen-drag' events from being sent.
+Prevent `touchscreen-drag' and translated mouse events from being
+sent until the touch sequence currently being translated ends.
+Must be called from a command bound to a `touchscreen-hold' or
+`touchscreen-drag' event.")
+(register-definition-prefixes "touch-screen" '("touch-screen-"))
 
 ;;; End of scraped data
 
diff --git a/lisp/loadup.el b/lisp/loadup.el
index 14152632da6..b56a5d92e2c 100644
--- a/lisp/loadup.el
+++ b/lisp/loadup.el
@@ -298,12 +298,9 @@
 (if (featurep 'dynamic-setting)
     (load "dynamic-setting"))
 
-;; touch-screen.el is tiny and is used liberally throughout the button
-;; code etc, so it may as well be preloaded everywhere.
-(load "touch-screen")
-
 (if (featurep 'x)
     (progn
+      (load "touch-screen")
       (load "x-dnd")
       (load "term/common-win")
       (load "term/x-win")))
@@ -316,6 +313,7 @@
 (if (featurep 'android)
     (progn
       (load "ls-lisp")
+      (load "touch-screen")
       (load "term/common-win")
       (load "term/android-win")))
 
@@ -389,6 +387,9 @@
     (load "tooltip"))
 (load "international/iso-transl") ; Binds Alt-[ and friends.
 
+;; Used by `kill-buffer', for instance.
+(load "emacs-lisp/rmc")
+
 ;; This file doesn't exist when building a development version of Emacs
 ;; from the repository.  It is generated just after temacs is built.
 (load "leim/leim-list.el" t)
@@ -408,8 +409,17 @@
       (message "Warning: Change in load-path due to site-load will be \
 lost after dumping")))
 
-;; Used by `kill-buffer', for instance.
-(load "emacs-lisp/rmc")
+;; Actively check for advised functions during preload since:
+;; - advices in Emacs's core are generally considered bad style;
+;; - `Snarf-documentation' looses docstrings of primitives advised
+;;   during preload (bug#66032#20).
+(mapatoms
+ (lambda (f)
+   (and (advice--p (symbol-function f))
+        ;; Don't make it an error because it's not serious enough and
+        ;; it can be annoying during development.  Also there are still
+        ;; circumstances where we use advice on preloaded functions.
+        (message "Warning: Advice installed on preloaded function %S" f))))
 
 ;; Make sure default-directory is unibyte when dumping.  This is
 ;; because we cannot decode and encode it correctly (since the locale
@@ -509,9 +519,9 @@ This to have it working when installed or if Emacs source
 directory got moved.  This is set to be a pair in the form of:
 \(rel-filename-from-install-bin . rel-filename-from-local-bin)."
   (when (and load--bin-dest-dir load--eln-dest-dir)
-    (setq eln-dest-dir
+      (setq eln-dest-dir
           (concat load--eln-dest-dir "native-lisp/" comp-native-version-dir 
"/"))
-    (maphash (lambda (_ cu)
+      (maphash (lambda (_ cu)
                (when (stringp (native-comp-unit-file cu))
                  (let* ((file (native-comp-unit-file cu))
                         (preloaded (equal (substring (file-name-directory file)
@@ -537,7 +547,7 @@ directory got moved.  This is set to be a pair in the form 
of:
 (defvar comp-subr-arities-h)
 (when (featurep 'native-compile)
   ;; Save the arity for all primitives so the compiler can always
-  ;; retrive it even in case of redefinition.
+  ;; retrieve it even in case of redefinition.
   (mapatoms (lambda (f)
               (when (subr-primitive-p (symbol-function f))
                 (puthash f (func-arity f) comp-subr-arities-h))))
diff --git a/lisp/mail/emacsbug.el b/lisp/mail/emacsbug.el
index 409ef7165fe..b927fcaed00 100644
--- a/lisp/mail/emacsbug.el
+++ b/lisp/mail/emacsbug.el
@@ -233,9 +233,11 @@ Already submitted bugs can be found in the Emacs bug 
tracker:
           (set-frame-parameter nil 'unsplittable nil))
       (error nil))
     (compose-mail report-emacs-bug-address topic)
+    (rfc822-goto-eoh)
+    (insert "X-Debbugs-Cc: \n")
     ;; The rest of this does not execute if the user was asked to
     ;; confirm and said no.
-    (when (eq major-mode 'message-mode)
+    (when (derived-mode-p 'message-mode)
       ;; Message-mode sorts the headers before sending.  We sort now so
       ;; that report-emacs-bug-orig-text remains valid.  (Bug#5178)
       (message-sort-headers)
diff --git a/lisp/mail/rmailout.el b/lisp/mail/rmailout.el
index 6d61dcd8208..ae483ef2d14 100644
--- a/lisp/mail/rmailout.el
+++ b/lisp/mail/rmailout.el
@@ -453,7 +453,7 @@ display message number MSG."
       (narrow-to-region (point-max) (point-max)))
     (insert-buffer-substring tembuf)
     (rmail-count-new-messages t)
-    ;; FIXME should re-use existing windows.
+    ;; FIXME should reuse existing windows.
     (if (rmail-summary-exists)
        (rmail-select-summary (rmail-update-summary)))
     (rmail-show-message-1 msg)))
diff --git a/lisp/man.el b/lisp/man.el
index 3efa29d7aad..1a5512c74f4 100644
--- a/lisp/man.el
+++ b/lisp/man.el
@@ -579,7 +579,7 @@ Otherwise, the value is whatever the function
 (defun Man-shell-file-name ()
   "Return a proper shell file name, respecting remote directories."
   (or ; This works also in the local case.
-      (with-connection-local-variables shell-file-name)
+      (connection-local-value shell-file-name)
       "/bin/sh"))
 
 (defun Man-header-file-path ()
diff --git a/lisp/mh-e/ChangeLog.1 b/lisp/mh-e/ChangeLog.1
index f918ab8fe74..011ed123986 100644
--- a/lisp/mh-e/ChangeLog.1
+++ b/lisp/mh-e/ChangeLog.1
@@ -7534,7 +7534,7 @@
        (mh-yank-cur-msg): Add a space between sexprs.
 
        * mh-utils.el (mh-mark-active-p): New macro which papers over
-       diffences between GNU Emacs and XEmacs. The variables mark-active
+       differences between GNU Emacs and XEmacs. The variables mark-active
        and transient-mark-mode are used in GNU Emacs while zmacs-regions
        and region-active-p are used in XEmacs.
 
diff --git a/lisp/mh-e/ChangeLog.2 b/lisp/mh-e/ChangeLog.2
index f0032e9db19..d4f650be5f4 100644
--- a/lisp/mh-e/ChangeLog.2
+++ b/lisp/mh-e/ChangeLog.2
@@ -2576,7 +2576,7 @@
        use function mh-variants instead.
        (mh-variant-info, mh-variant-mh-info, mh-variant-mu-mh-info)
        (mh-variant-nmh-info): Co-locate next to mh-variants, which uses
-       them.  Updated to use mh-file-command-p which is more accurrate
+       them.  Updated to use mh-file-command-p which is more accurate
        than file-executable-p which returns t for directories.
        (mh-file-command-p): Move here from mh-utils, since
        mh-variant-*-info are the only functions to use it.
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index 46906a3dc7d..b0a6f38dd3b 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -963,6 +963,8 @@ is at its default value `grow-only'."
                (reverse multi-message-list)
                multi-message-separator)))
 
+(defvar touch-screen-current-tool)
+
 (defun clear-minibuffer-message ()
   "Clear message temporarily shown in the minibuffer.
 Intended to be called via `clear-message-function'."
@@ -977,7 +979,7 @@ Intended to be called via `clear-message-function'."
   ;; progress, because a preview message might currently be displayed
   ;; in the echo area.  FIXME: find some way to place this in
   ;; touch-screen.el.
-  (if (and touch-screen-preview-select
+  (if (and (bound-and-true-p touch-screen-preview-select)
            (eq (nth 3 touch-screen-current-tool) 'drag))
       'dont-clear-message
     ;; Return nil telling the caller that the message
@@ -1316,14 +1318,29 @@ completion candidates than this number."
 (defcustom completions-sort 'alphabetical
   "Sort candidates in the *Completions* buffer.
 
-The value can be nil to disable sorting, `alphabetical' for
-alphabetical sorting or a custom sorting function.  The sorting
-function takes and returns a list of completion candidate
-strings."
+Completion candidates in the *Completions* buffer are sorted
+depending on the value.
+
+If it's nil, sorting is disabled.
+If it's the symbol `alphabetical', candidates are sorted by
+`minibuffer-sort-alphabetically'.
+If it's the symbol `historical', candidates are sorted by
+`minibuffer-sort-by-history', which first sorts alphabetically,
+and then rearranges the order according to the order of the
+candidates in the minibuffer history.
+If it's a function, the function is called to sort the candidates.
+The sorting function takes a list of completion candidate
+strings, which it may modify; it should return a sorted list,
+which may be the same.
+
+If the completion-specific metadata provides a
+`display-sort-function', that function overrides the value of
+this variable."
   :type '(choice (const :tag "No sorting" nil)
                  (const :tag "Alphabetical sorting" alphabetical)
+                 (const :tag "Historical sorting" historical)
                  (function :tag "Custom function"))
-  :version "29.1")
+  :version "30.1")
 
 (defcustom completions-group nil
   "Enable grouping of completion candidates in the *Completions* buffer.
@@ -1649,6 +1666,44 @@ Remove completion BASE prefix string from history 
elements."
                      (substring c base-size)))
                  hist)))))
 
+(defun minibuffer-sort-alphabetically (completions)
+  "Sort COMPLETIONS alphabetically.
+
+COMPLETIONS are sorted alphabetically by `string-lessp'.
+
+This is a suitable function to use for `completions-sort' or to
+include as `display-sort-function' in completion metadata."
+  (sort completions #'string-lessp))
+
+(defvar minibuffer-completion-base nil
+  "The base for the current completion.
+
+This is the part of the current minibuffer input which comes
+before the current completion field, as determined by
+`completion-boundaries'.  This is primarily relevant for file
+names, where this is the directory component of the file name.")
+
+(defun minibuffer-sort-by-history (completions)
+  "Sort COMPLETIONS by their position in `minibuffer-history-variable'.
+
+COMPLETIONS are sorted first by `minibuffer-sort-alphbetically',
+then any elements occurring in the minibuffer history list are
+moved to the front based on the chronological order they occur in
+the history.  If a history variable hasn't been specified for
+this call of `completing-read', COMPLETIONS are sorted only by
+`minibuffer-sort-alphbetically'.
+
+This is a suitable function to use for `completions-sort' or to
+include as `display-sort-function' in completion metadata."
+  (let ((alphabetized (sort completions #'string-lessp)))
+    ;; Only use history when it's specific to these completions.
+    (if (eq minibuffer-history-variable
+            (default-value minibuffer-history-variable))
+        alphabetized
+      (minibuffer--sort-by-position
+       (minibuffer--sort-preprocess-history minibuffer-completion-base)
+       alphabetized))))
+
 (defun minibuffer--group-by (group-fun sort-fun elems)
   "Group ELEMS by GROUP-FUN and sort groups by SORT-FUN."
   (let ((groups))
@@ -2312,8 +2367,11 @@ candidates."
 
     (with-current-buffer standard-output
       (goto-char (point-max))
-      (when completions-header-format
-        (insert (format completions-header-format (length completions))))
+      (if completions-header-format
+          (insert (format completions-header-format (length completions)))
+        (unless completion-show-help
+          ;; Ensure beginning-of-buffer isn't a completion.
+          (insert (propertize "\n" 'face '(:height 0)))))
       (completion--insert-strings completions group-fun)))
 
   (run-hooks 'completion-setup-hook)
@@ -2380,6 +2438,36 @@ These include:
         (resize-temp-buffer-window win))
     (fit-window-to-buffer win completions-max-height)))
 
+(defcustom completion-auto-deselect t
+  "If non-nil, deselect current completion candidate when you type in 
minibuffer.
+
+A non-nil value means that after typing at the minibuffer prompt,
+any completion candidate highlighted in *Completions* window (to
+indicate that it is the selected candidate) will be un-highlighted,
+and point in the *Completions* window will be moved off such a candidate.
+This means that `RET' (`minibuffer-choose-completion-or-exit') will exit
+the minubuffer with the minibuffer's current contents, instead of the
+selected completion candidate."
+  :type '(choice (const :tag "Candidates in *Completions* stay selected as you 
type" nil)
+                 (const :tag "Typing deselects any completion candidate in 
*Completions*" t))
+  :version "30.1")
+
+(defun completions--deselect ()
+  "If point is in a completion candidate, move to just after the end of it.
+
+The candidate will still be chosen by `choose-completion' unless
+`choose-completion-deselect-if-after' is non-nil."
+  (when (get-text-property (point) 'completion--string)
+    (goto-char (or (next-single-property-change (point) 'completion--string)
+                   (point-max)))))
+
+(defun completions--after-change (_start _end _old-len)
+  "Update displayed *Completions* buffer after change in buffer contents."
+  (when completion-auto-deselect
+    (when-let (window (get-buffer-window "*Completions*" 0))
+      (with-selected-window window
+        (completions--deselect)))))
+
 (defun minibuffer-completion-help (&optional start end)
   "Display a list of possible completions of the current minibuffer contents."
   (interactive)
@@ -2402,6 +2490,7 @@ These include:
           ;; If there are no completions, or if the current input is already
           ;; the sole completion, then hide (previous&stale) completions.
           (minibuffer-hide-completions)
+          (remove-hook 'after-change-functions #'completions--after-change t)
           (if completions
               (completion--message "Sole completion")
             (unless completion-fail-discreetly
@@ -2411,6 +2500,7 @@ These include:
       (let* ((last (last completions))
              (base-size (or (cdr last) 0))
              (prefix (unless (zerop base-size) (substring string 0 base-size)))
+             (minibuffer-completion-base (substring string 0 base-size))
              (base-prefix (buffer-substring (minibuffer--completion-prompt-end)
                                             (+ start base-size)))
              (base-suffix
@@ -2462,6 +2552,8 @@ These include:
             (body-function
              . ,#'(lambda (_window)
                     (with-current-buffer mainbuf
+                      (when completion-auto-deselect
+                        (add-hook 'after-change-functions 
#'completions--after-change nil t))
                       ;; Remove the base-size tail because `sort' requires a 
properly
                       ;; nil-terminated list.
                       (when last (setcdr last nil))
@@ -2475,7 +2567,8 @@ These include:
                                             (funcall sort-fun completions)
                                           (pcase completions-sort
                                             ('nil completions)
-                                            ('alphabetical (sort completions 
#'string-lessp))
+                                            ('alphabetical 
(minibuffer-sort-alphabetically completions))
+                                            ('historical 
(minibuffer-sort-by-history completions))
                                             (_ (funcall completions-sort 
completions)))))
 
                       ;; After sorting, group the candidates using the
@@ -3017,7 +3110,6 @@ displaying the *Completions* buffer exists."
   "<down>"  (minibuffer-visible-completions-bind 
#'minibuffer-next-line-completion)
   "RET"     (minibuffer-visible-completions-bind 
#'minibuffer-choose-completion-or-exit)
   "C-g"     (minibuffer-visible-completions-bind 
#'minibuffer-hide-completions))
-
 
 ;;; Completion tables.
 
@@ -4675,7 +4767,8 @@ insert the selected completion candidate to the 
minibuffer."
           (next-line-completion (or n 1))
         (next-completion (or n 1)))
       (when auto-choose
-        (let ((completion-use-base-affixes t))
+        (let ((completion-use-base-affixes t)
+              (completion-auto-deselect nil))
           (choose-completion nil t t))))))
 
 (defun minibuffer-previous-completion (&optional n)
@@ -4723,7 +4816,8 @@ in the completions window, then exit the minibuffer using 
its present
 contents."
   (interactive "P")
   (condition-case nil
-      (minibuffer-choose-completion no-exit no-quit)
+      (let ((choose-completion-deselect-if-after t))
+        (minibuffer-choose-completion no-exit no-quit))
     (error (minibuffer-complete-and-exit))))
 
 (defun minibuffer-complete-history ()
@@ -4850,7 +4944,7 @@ This is run upon minibuffer setup."
 (defun minibuffer-exit-on-screen-keyboard ()
   "Hide the on-screen keyboard if it was displayed.
 Hide the on-screen keyboard in a timer set to run in 0.1 seconds.
-It will be cancelled if the minibuffer is displayed again within
+It will be canceled if the minibuffer is displayed again within
 that timeframe.
 
 Do not hide the on screen keyboard inside a recursive edit.
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index 3d64b7976b3..4e4db34a78d 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -2850,7 +2850,8 @@ NO-ERROR, if a listing for DIRECTORY cannot be obtained."
                                   (ange-ftp-switches-ok dired-actual-switches))
                              (and (boundp 'dired-listing-switches)
                                   (ange-ftp-switches-ok
-                                   dired-listing-switches))
+                                   (connection-local-value
+                                     dired-listing-switches)))
                              "-al")
                          t no-error)
             (gethash directory ange-ftp-files-hashtable)))))
diff --git a/lisp/net/newst-treeview.el b/lisp/net/newst-treeview.el
index 39988ba6cfb..3b2714f3cc4 100644
--- a/lisp/net/newst-treeview.el
+++ b/lisp/net/newst-treeview.el
@@ -1466,7 +1466,7 @@ Move to next item unless DONT-PROCEED is non-nil."
       nil)))
 
 (defun newsticker--treeview-get-second-child (node)
-  "Get scond child of NODE."
+  "Get second child of NODE."
   (let ((children (widget-get node :children)))
     (if children
         (car (cdr children))
diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index 9f030b4c743..ec9fb1573ac 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -200,7 +200,7 @@ inline if it occupies less than this fraction of window 
width.
 
 HEIGHT can be also be an integer or a floating point number.  If it is an
 integer and the pixel height of an image exceeds it, the image image is
-displyed on a separate line.  If it is a float number , the limit is
+displayed on a separate line.  If it is a float number , the limit is
 interpreted as a multiple of the height of default font."
   :version "30.1"
   :type '(choice (const nil) (cons number number)))
@@ -1137,7 +1137,9 @@ element is the data blob and the second element is the 
content-type."
         (when image
           ;; The trailing space can confuse shr-insert into not
           ;; putting any space after inline images.
-         (setq alt (string-trim alt))
+          ;; ALT may be nil when visiting image URLs in eww
+          ;; (bug#67764).
+         (setq alt (if alt (string-trim alt) "*"))
          ;; When inserting big-ish pictures, put them at the
          ;; beginning of the line.
          (let ((inline (shr--inline-image-p image)))
@@ -1146,8 +1148,8 @@ element is the data blob and the second element is the 
content-type."
                (insert "\n"))
            (let ((image-pos (point)))
              (if (eq size 'original)
-                 (insert-sliced-image image (or alt "*") nil 20 1)
-               (insert-image image (or alt "*")))
+                 (insert-sliced-image image alt nil 20 1)
+               (insert-image image alt))
              (put-text-property start (point) 'image-size size)
              (when (and (not inline) shr-max-inline-image-size)
                (insert "\n"))
diff --git a/lisp/net/sieve-manage.el b/lisp/net/sieve-manage.el
index 81f50e74987..cfc748c9387 100644
--- a/lisp/net/sieve-manage.el
+++ b/lisp/net/sieve-manage.el
@@ -171,8 +171,8 @@ Valid states are `closed', `initial', `nonauth', and 
`auth'.")
   "Append ARGS to sieve-manage log buffer.
 
 ARGS can be a string or a list of strings.
-The buffer to use for logging is specifified via
-`sieve-manage-log'. If it is nil, logging is disabled."
+The buffer to use for logging is specified via `sieve-manage-log'.
+If it is nil, logging is disabled."
   (when sieve-manage-log
     (with-current-buffer (or (get-buffer sieve-manage-log)
                              (with-current-buffer
diff --git a/lisp/net/soap-client.el b/lisp/net/soap-client.el
index b2bb59a25a0..e6053007475 100644
--- a/lisp/net/soap-client.el
+++ b/lisp/net/soap-client.el
@@ -1956,7 +1956,7 @@ This is a specialization of `soap-decode-type' for
                                   (xml-get-children node (intern e-name)))
                               ;; e-name is nil so a) we don't know which
                               ;; children to operate on, and b) we want to
-                              ;; re-use soap-decode-xs-complex-type, which
+                              ;; reuse soap-decode-xs-complex-type, which
                               ;; expects a node argument with a complex
                               ;; type; therefore we need to operate on the
                               ;; entire node.  We wrap node in a list so
diff --git a/lisp/net/tramp-cache.el b/lisp/net/tramp-cache.el
index 6ecb80f09b2..7c4e4d68a14 100644
--- a/lisp/net/tramp-cache.el
+++ b/lisp/net/tramp-cache.el
@@ -340,7 +340,7 @@ Preserve timestamps."
   (declare (indent 3) (debug t))
   `(progn
      ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-     (setq ,key (tramp-file-name-unify ,key ,file))
+     (setf ,key (tramp-file-name-unify ,key ,file))
      (let* ((hash (tramp-get-hash-table ,key))
            (cached (and (hash-table-p hash) (gethash ,property hash))))
        (unwind-protect (progn ,@body)
@@ -358,7 +358,7 @@ Preserve timestamps."
   (declare (indent 3) (debug t))
   `(progn
      ;; Unify localname.  Remove hop from `tramp-file-name' structure.
-     (setq ,key (tramp-file-name-unify ,key ,file))
+     (setf ,key (tramp-file-name-unify ,key ,file))
      (let* ((hash (tramp-get-hash-table ,key))
            (values
             (and (hash-table-p hash)
@@ -474,7 +474,7 @@ used to cache connection properties of the local machine."
   "Save PROPERTY, run BODY, reset PROPERTY."
   (declare (indent 2) (debug t))
   `(progn
-     (setq ,key (tramp-file-name-unify ,key))
+     (setf ,key (tramp-file-name-unify ,key))
      (let* ((hash (tramp-get-hash-table ,key))
            (cached (and (hash-table-p hash)
                         (gethash ,property hash tramp-cache-undefined))))
@@ -491,7 +491,7 @@ used to cache connection properties of the local machine."
 PROPERTIES is a list of file properties (strings)."
   (declare (indent 2) (debug t))
   `(progn
-     (setq ,key (tramp-file-name-unify ,key))
+     (setf ,key (tramp-file-name-unify ,key))
      (let* ((hash (tramp-get-hash-table ,key))
            (values
             (mapcar
diff --git a/lisp/net/tramp-compat.el b/lisp/net/tramp-compat.el
index 7c10c6530e9..e05f371f406 100644
--- a/lisp/net/tramp-compat.el
+++ b/lisp/net/tramp-compat.el
@@ -61,6 +61,7 @@
 ;; avoid them in cases we know what we do.
 (defmacro tramp-compat-funcall (function &rest arguments)
   "Call FUNCTION with ARGUMENTS if it exists.  Do not raise compiler warnings."
+  (declare (indent 1) (debug t))
   `(when (functionp ,function)
      (with-no-warnings (funcall ,function ,@arguments))))
 
@@ -306,6 +307,16 @@ Also see `ignore'."
       ?\N{KHMER SIGN CAMNUC PII KUUH})
     "List of characters equivalent to trailing colon in \"password\" 
prompts."))
 
+;; Macro `connection-local-p' is new in Emacs 30.1.
+(if (macrop 'connection-local-p)
+    (defalias 'tramp-compat-connection-local-p #'connection-local-p)
+  (defmacro tramp-compat-connection-local-p (variable)
+    "Non-nil if VARIABLE has a connection-local binding in 
`default-directory'."
+    `(let (connection-local-variables-alist file-local-variables-alist)
+       (hack-connection-local-variables
+       (connection-local-criteria-for-default-directory))
+       (and (assq ',variable connection-local-variables-alist) t))))
+
 (dolist (elt (all-completions "tramp-compat-" obarray 'functionp))
   (function-put (intern elt) 'tramp-suppress-trace t))
 
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index 587b9db067a..0680fcbe8c9 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -148,6 +148,8 @@ If NAME doesn't belong to an encrypted remote directory, 
return nil."
     (and tramp-crypt-enabled (stringp name)
         (not (file-name-quoted-p name))
         (not (string-suffix-p tramp-crypt-encfs-config name))
+        ;; No lock file name.
+        (not (string-prefix-p ".#" (file-name-nondirectory name)))
         (dolist (dir tramp-crypt-directories)
           (and (string-prefix-p
                 dir (file-name-as-directory (expand-file-name name)))
@@ -157,7 +159,7 @@ If NAME doesn't belong to an encrypted remote directory, 
return nil."
 ;; New handlers should be added here.
 ;;;###tramp-autoload
 (defconst tramp-crypt-file-name-handler-alist
-  '(;; `abbreviate-file-name' performed by default handler.
+  '((abbreviate-file-name . identity)
     (access-file . tramp-crypt-handle-access-file)
     (add-name-to-file . tramp-handle-add-name-to-file)
     ;; `byte-compiler-base-file-name' performed by default handler.
@@ -492,7 +494,7 @@ See `tramp-crypt-do-encrypt-or-decrypt-file'."
 
 ;;;###tramp-autoload
 (defun tramp-crypt-add-directory (name)
-  "Mark remote directory NAME for encryption.
+  "Mark expanded remote directory NAME for encryption.
 Files in that directory and all subdirectories will be encrypted
 before copying to, and decrypted after copying from that
 directory.  File names will be also encrypted."
@@ -516,7 +518,7 @@ directory.  File names will be also encrypted."
  #'tramp-crypt-command-completion-p)
 
 (defun tramp-crypt-remove-directory (name)
-  "Unmark remote directory NAME for encryption.
+  "Unmark expanded remote directory NAME for encryption.
 Existing files in that directory and its subdirectories will be
 kept in their encrypted form."
   ;; (declare (completion tramp-crypt-command-completion-p))
@@ -853,6 +855,23 @@ WILDCARD is not supported."
     (tramp-compat-funcall
      'unlock-file (tramp-crypt-encrypt-file-name filename))))
 
+(defun tramp-crypt-cleanup-connection (vec)
+  "Cleanup crypt resources determined by VEC."
+  (let ((tramp-cleanup-connection-hook
+        (remove
+         #'tramp-crypt-cleanup-connection tramp-cleanup-connection-hook))
+       (tramp-crypt-enabled t))
+    (dolist (dir tramp-crypt-directories)
+      (when (tramp-file-name-equal-p vec (tramp-dissect-file-name dir))
+       (tramp-cleanup-connection (tramp-crypt-dissect-file-name dir))))))
+
+;; Add cleanup hooks.
+(add-hook 'tramp-cleanup-connection-hook #'tramp-crypt-cleanup-connection)
+(add-hook 'tramp-crypt-unload-hook
+         (lambda ()
+           (remove-hook 'tramp-cleanup-connection-hook
+                        #'tramp-crypt-cleanup-connection)))
+
 (with-eval-after-load 'bookmark
   (add-hook 'bookmark-inhibit-context-functions
            #'tramp-crypt-file-name-p)
diff --git a/lisp/net/tramp-message.el b/lisp/net/tramp-message.el
index 8afc8d5fd87..e05357f1f4f 100644
--- a/lisp/net/tramp-message.el
+++ b/lisp/net/tramp-message.el
@@ -515,7 +515,7 @@ This shouldn't be changed globally, but let-bind where 
needed.")
 Bound in `tramp-*-file-name-handler' functions.")
 
 (defun tramp-debug-message-buttonize (position)
-  "Buttonize function in current buffer, at next line starting after POSTION."
+  "Buttonize function in current buffer, at next line starting after POSITION."
   (declare (tramp-suppress-trace t))
   (save-excursion
     (goto-char position)
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index 3b47dafcb46..a7ead1f2997 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -521,8 +521,8 @@ The string is used in `tramp-methods'.")
  (tramp-set-completion-function "fcp" tramp-completion-function-alist-ssh))
 
 (defcustom tramp-sh-extra-args
-  `((,(rx "/bash" eos) . "-noediting -norc -noprofile")
-    (,(rx "/zsh" eos) . "-f +Z -V"))
+  `((,(rx (| bos "/") "bash" eos) . "-noediting -norc -noprofile")
+    (,(rx (| bos "/") "zsh" eos) . "-f +Z -V"))
   "Alist specifying extra arguments to pass to the remote shell.
 Entries are (REGEXP . ARGS) where REGEXP is a regular expression
 matching the shell file name and ARGS is a string specifying the
@@ -533,7 +533,7 @@ This variable is only used when Tramp needs to start up 
another shell
 for tilde expansion.  The extra arguments should typically prevent the
 shell from reading its init file."
   :group 'tramp
-  :version "27.1"
+  :version "30.1"
   :type '(alist :key-type regexp :value-type string))
 
 (defconst tramp-actions-before-shell
@@ -1239,7 +1239,7 @@ Operations not mentioned here will be handled by the 
normal Emacs functions.")
       (with-current-buffer (tramp-get-connection-buffer v)
        (goto-char (point-min))
        (tramp-set-file-property v localname "file-symlink-marker" (read 
(current-buffer)))
-       ;; We cannote call `read', the file name isn't quoted.
+       ;; We cannot call `read', the file name isn't quoted.
        (forward-line)
        (buffer-substring (point) (line-end-position))))
 
@@ -2523,7 +2523,7 @@ The method used must be an out-of-band method."
                      (tramp-get-connection-name v)
                      (tramp-get-connection-buffer v)
                      copy-program copy-args)))
-               ;; This is neded for ssh or PuTTY based processes, and
+               ;; This is needed for ssh or PuTTY based processes, and
                ;; only if the respective options are set.  Perhaps,
                ;; the setting could be more fine-grained.
                ;; (process-put p 'tramp-shared-socket t)
@@ -3847,7 +3847,7 @@ Fall back to normal file name handler if no Tramp handler 
exists."
           v 'file-notify-error
           "`%s' failed to start on remote host"
           (string-join sequence " "))
-       ;; This is neded for ssh or PuTTY based processes, and only if
+       ;; This is needed for ssh or PuTTY based processes, and only if
        ;; the respective options are set.  Perhaps, the setting could
        ;; be more fine-grained.
        ;; (process-put p 'tramp-shared-socket t)
@@ -5255,7 +5255,7 @@ connection if a previous connection has died for some 
reason."
                              (and tramp-encoding-command-interactive
                                   `(,tramp-encoding-command-interactive)))))))
 
-                 ;; This is neded for ssh or PuTTY based processes,
+                 ;; This is needed for ssh or PuTTY based processes,
                  ;; and only if the respective options are set.
                  ;; Perhaps, the setting could be more fine-grained.
                  ;; (process-put p 'tramp-shared-socket t)
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 3baad82dda1..88cbfa2d88c 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -3328,7 +3328,7 @@ BODY is the backend specific code."
     (with-parsed-tramp-file-name (expand-file-name ,directory) nil
       (tramp-barf-if-file-missing v ,directory
        (when (file-directory-p ,directory)
-         (setq ,directory
+         (setf ,directory
                (file-name-as-directory (expand-file-name ,directory)))
          (let ((temp
                 (with-tramp-file-property v localname "directory-files" 
,@body))
@@ -3499,7 +3499,7 @@ on the same host.  Otherwise, TARGET is quoted."
      (let ((non-essential t))
        (when (and (tramp-tramp-file-p ,target)
                  (tramp-file-name-equal-p v (tramp-dissect-file-name ,target)))
-        (setq ,target (tramp-file-local-name (expand-file-name ,target))))
+        (setf ,target (tramp-file-local-name (expand-file-name ,target))))
        ;; There could be a cyclic link.
        (tramp-flush-file-properties
        v (expand-file-name ,target (tramp-file-local-name default-directory))))
@@ -4946,7 +4946,7 @@ a connection-local variable."
            ;; Query flag is overwritten in `tramp-post-process-creation',
            ;; so we reset it.
            (set-process-query-on-exit-flag p (null noquery))
-           ;; This is neded for ssh or PuTTY based processes, and
+           ;; This is needed for ssh or PuTTY based processes, and
            ;; only if the respective options are set.  Perhaps, the
            ;; setting could be more fine-grained.
            ;; (process-put p 'tramp-shared-socket t)
diff --git a/lisp/org/ChangeLog.1 b/lisp/org/ChangeLog.1
index 82b1c832c40..ea3a0424c3c 100644
--- a/lisp/org/ChangeLog.1
+++ b/lisp/org/ChangeLog.1
@@ -12523,7 +12523,7 @@
 2012-01-03  Carsten Dominik  <carsten.dominik@gmail.com>  (tiny change)
 
        * org-clock.el (org-clock-in, org-clock-find-position):
-       Remove erraneous space in regexp.
+       Remove erroneous space in regexp.
 
 2012-01-03  Eric Schulte  <eric.schulte@gmx.com>
 
@@ -12700,7 +12700,7 @@
 2012-01-03  Carsten Dominik  <carsten.dominik@gmail.com>  (tiny change)
 
        * org-clock.el (org-clock-in, org-clock-find-position):
-       Remove erraneous space in regexp.
+       Remove erroneous space in regexp.
 
 2012-01-03  Jambunathan K  <kjambunathan@gmail.com>
 
@@ -14573,7 +14573,7 @@
 
 2012-01-03  Nicolas Goaziou  <n.goaziou@gmail.com>
 
-       * org-footnote.el (org-footnote-at-definition-p): Re-use
+       * org-footnote.el (org-footnote-at-definition-p): Reuse
        `org-footnote-definition-re'.
 
 2012-01-03  Nicolas Goaziou  <n.goaziou@gmail.com>
@@ -18471,7 +18471,7 @@
 
        * org-list.el (org-in-item-p): When point was just after
        org-list-end-re, check wouldn't be done for starting line.  So, if
-       the first line was an item, it wouln't be noticed and function
+       the first line was an item, it wouldn't be noticed and function
        would return nil.  Simplify and comment code.
 
 2011-07-28  Nicolas Goaziou  <n.goaziou@gmail.com>
@@ -19554,7 +19554,7 @@
 
 2011-07-28  Julien Danjou  <julien@danjou.info>
 
-       * org-agenda.el (org-format-agenda-item): Simplify time comuting.
+       * org-agenda.el (org-format-agenda-item): Simplify time computing.
 
 2011-07-28  Nicolas Goaziou  <n.goaziou@gmail.com>
 
@@ -22539,7 +22539,7 @@
 
 2010-11-11  Dan Davison  <davison@stats.ox.ac.uk>
 
-       * org-src.el (org-src-font-lock-fontify-block): Re-use hidden
+       * org-src.el (org-src-font-lock-fontify-block): Reuse hidden
        language major mode buffers during fontification.
 
 2010-11-11  Dan Davison  <davison@stats.ox.ac.uk>
@@ -26729,7 +26729,7 @@
 2009-11-20  Eric Schulte  <schulte.eric@gmail.com>
 
        * org-exp-blocks.el (org-export-blocks-format-ditaa): Use sha1
-       hash keys to cache and re-use images generated by the
+       hash keys to cache and reuse images generated by the
        org-exp-blocks interface to ditaa and dot.
 
        * org.el (org-format-latex): Latex images are now saved to files
@@ -29300,7 +29300,7 @@
        statistics.
        (org-hierarchical-checkbox-statistics): New option.
 
-       * org.el (org-cycle): Remove erraneous space character.
+       * org.el (org-cycle): Remove erroneous space character.
 
        * org-icalendar.el (org-icalendar-timezone): Initialize from
        environment.
diff --git a/lisp/org/ob-plantuml.el b/lisp/org/ob-plantuml.el
index 3202c6e415d..febdb3964c6 100644
--- a/lisp/org/ob-plantuml.el
+++ b/lisp/org/ob-plantuml.el
@@ -57,7 +57,7 @@ The JAR can be configured via `org-plantuml-jar-path'.
 
 `plantuml' means to use the PlantUML executable.
 The executable can be configured via `org-plantuml-executable-path'.
-You can also configure extra arguments via `org-plantuml-executable-args'."
+You can also configure extra arguments via `org-plantuml-args'."
   :group 'org-babel
   :package-version '(Org . "9.4")
   :type 'symbol
diff --git a/lisp/org/oc-biblatex.el b/lisp/org/oc-biblatex.el
index b2d31f0f635..0ed5459a66d 100644
--- a/lisp/org/oc-biblatex.el
+++ b/lisp/org/oc-biblatex.el
@@ -26,7 +26,7 @@
 
 ;; The processor relies on "biblatex" LaTeX package.  As such it ensures that
 ;; the package is properly required in the document's preamble.  More
-;; accurately, it will re-use any "\usepackage{biblatex}" already present in
+;; accurately, it will reuse any "\usepackage{biblatex}" already present in
 ;; the document (e.g., through `org-latex-packages-alist'), or insert one using
 ;; options defined in `org-cite-biblatex-options'.
 
diff --git a/lisp/org/oc.el b/lisp/org/oc.el
index 8a7b662098a..269f7fd13a1 100644
--- a/lisp/org/oc.el
+++ b/lisp/org/oc.el
@@ -52,7 +52,7 @@
 ;; through the "cite_export" keyword.
 
 ;; Eventually, this library provides some tools, mainly targeted at
-;; processor implementors.  Most are export-specific and are located
+;; processor implementers.  Most are export-specific and are located
 ;; in the "Tools only available during export" and "Tools generating
 ;; or operating on parsed data" sections.
 
diff --git a/lisp/org/org-capture.el b/lisp/org/org-capture.el
index a696c615b2a..41872ff87ef 100644
--- a/lisp/org/org-capture.el
+++ b/lisp/org/org-capture.el
@@ -1312,7 +1312,7 @@ may have been stored before."
                (while (< (point) end)
                  (indent-to i)
                  (forward-line)))
-             ;; Pre-pending an item could change the type of the list
+             ;; Prepending an item could change the type of the list
              ;; if there is a mismatch.  In this situation,
              ;; prioritize the existing list.
              (when prepend?
diff --git a/lisp/org/org-compat.el b/lisp/org/org-compat.el
index d5bf2191ae7..db5e9283bf5 100644
--- a/lisp/org/org-compat.el
+++ b/lisp/org/org-compat.el
@@ -141,7 +141,7 @@ Unibyte strings are converted to multibyte for comparison."
 Elements in COMPONENTS must be a string or nil.
 DIRECTORY or the non-final elements in COMPONENTS may or may not end
 with a slash -- if they don't end with a slash, a slash will be
-inserted before contatenating."
+inserted before concatenating."
     (save-match-data
       (mapconcat
        #'identity
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index 0dd149762c4..34eb27b6465 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -5484,7 +5484,7 @@ This variable is used to determine when re-parsing buffer 
is not going
 to slow down the command.
 
 If the commands end up modifying the cache, the worst case scenario is
-performance drop.  So, advicing these commands is safe.  Yet, it is
+performance drop.  So, advising these commands is safe.  Yet, it is
 better to remove the commands advised in such a way from this list.")
 
 (defmacro org-element--request-key (request)
@@ -5906,7 +5906,7 @@ If this warning appears regularly, please report the 
warning text to Org mode ma
        (org-element-property :begin element)
        (org-element-property :org-element--cache-sync-key element))
       (org-element-cache-reset)
-      (throw 'quit nil))
+      (throw 'org-element--cache-quit nil))
     (or (avl-tree-delete org-element--cache element)
         (progn
           ;; This should not happen, but if it is, would be better to know
@@ -5919,7 +5919,7 @@ If this warning appears regularly, please report the 
warning text to Org mode ma
            (org-element-property :begin element)
            (org-element-property :org-element--cache-sync-key element))
           (org-element-cache-reset)
-          (throw 'quit nil)))))
+          (throw 'org-element--cache-quit nil)))))
 
 ;;;; Synchronization
 
@@ -6382,6 +6382,10 @@ completing the request."
                          ;; We altered the tree structure.  The tree
                          ;; traversal needs to be restarted.
                          (setf (org-element--request-key request) key)
+                         ;; Make sure that we restart tree traversal
+                         ;; past already shifted elements (before the
+                         ;; removed DATA).
+                         (setq start key)
                          (setf (org-element--request-parent request) parent)
                          ;; Restart tree traversal.
                          (setq node (org-element--cache-root)
diff --git a/lisp/org/org-macs.el b/lisp/org/org-macs.el
index 4efa8ba6800..6ed901b7397 100644
--- a/lisp/org/org-macs.el
+++ b/lisp/org/org-macs.el
@@ -1119,7 +1119,12 @@ Return width in pixels when PIXELS is non-nil."
             (setq pixel-width
                   (if (get-buffer-window (current-buffer))
                       (car (window-text-pixel-size
-                            nil (line-beginning-position) (point-max)))
+                            ;; FIXME: 10000 because
+                            ;; `most-positive-fixnum' ain't working
+                            ;; (tests failing) and this call will be
+                            ;; removed after we drop Emacs 28 support
+                            ;; anyway.
+                            nil (line-beginning-position) (point-max) 10000))
                     (let ((dedicatedp (window-dedicated-p))
                           (oldbuffer (window-buffer)))
                       (unwind-protect
@@ -1128,7 +1133,7 @@ Return width in pixels when PIXELS is non-nil."
                             (set-window-dedicated-p nil nil)
                             (set-window-buffer nil (current-buffer))
                             (car (window-text-pixel-size
-                                  nil (line-beginning-position) (point-max))))
+                                  nil (line-beginning-position) (point-max) 
10000)))
                         (set-window-buffer nil oldbuffer)
                         (set-window-dedicated-p nil dedicatedp)))))
             (unless pixels
@@ -1137,7 +1142,7 @@ Return width in pixels when PIXELS is non-nil."
               (setq symbol-width
                     (if (get-buffer-window (current-buffer))
                         (car (window-text-pixel-size
-                              nil (line-beginning-position) (point-max)))
+                              nil (line-beginning-position) (point-max) 10000))
                       (let ((dedicatedp (window-dedicated-p))
                             (oldbuffer (window-buffer)))
                         (unwind-protect
@@ -1146,7 +1151,7 @@ Return width in pixels when PIXELS is non-nil."
                               (set-window-dedicated-p nil nil)
                               (set-window-buffer nil (current-buffer))
                               (car (window-text-pixel-size
-                                    nil (line-beginning-position) 
(point-max))))
+                                    nil (line-beginning-position) (point-max) 
10000)))
                           (set-window-buffer nil oldbuffer)
                           (set-window-dedicated-p nil dedicatedp)))))))
           (if pixels
diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el
index 01078f4596d..59ef2ac27a0 100644
--- a/lisp/org/org-persist.el
+++ b/lisp/org/org-persist.el
@@ -111,7 +111,7 @@
 ;;
 ;; Each collection is represented as a plist containing the following
 ;; properties:
-;; - `:container'   : list of data continers to be stored in single
+;; - `:container'   : list of data containers to be stored in single
 ;;                    file;
 ;; - `:persist-file': data file name;
 ;; - `:associated'  : list of associated objects;
@@ -253,7 +253,7 @@ The index is a list of plists.  Each plist contains 
information about
 persistent data storage.  Each plist contains the following
 properties:
 
-  - `:container'  : list of data continers to be stored in single file
+  - `:container'  : list of data containers to be stored in single file
   - `:persist-file': data file name
   - `:associated'  : list of associated objects
   - `:last-access' : last date when the container has been read
@@ -481,9 +481,14 @@ MISC, if non-nil will be appended to the collection.  It 
must be a plist."
      (unless (stringp associated)
        (setq associated (cadr associated)))
      (let* ((rtn `(:file ,associated))
-            (inode (and (fboundp 'file-attribute-inode-number)
-                        (file-attribute-inode-number
-                         (file-attributes associated)))))
+            (inode (and
+                    ;; Do not store :inode for remote files - it may
+                    ;; be time-consuming on slow connections or even
+                    ;; fail completely when ssh connection is closed.
+                    (not (file-remote-p associated))
+                    (fboundp 'file-attribute-inode-number)
+                    (file-attribute-inode-number
+                     (file-attributes associated)))))
        (when inode (plist-put rtn :inode inode))
        rtn))
     ((or (pred bufferp) `(:buffer ,_))
@@ -501,6 +506,10 @@ MISC, if non-nil will be appended to the collection.  It 
must be a plist."
                      (or (buffer-base-buffer associated)
                          associated)))
          (setq inode (when (and file
+                                ;; Do not store :inode for remote files - it 
may
+                                ;; be time-consuming on slow connections or 
even
+                                ;; fail completely when ssh connection is 
closed.
+                                (not (file-remote-p file))
                                 (fboundp 'file-attribute-inode-number))
                        (file-attribute-inode-number
                         (file-attributes file))))
diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el
index aa819aa7d2f..d6b7086cddd 100644
--- a/lisp/org/org-table.el
+++ b/lisp/org/org-table.el
@@ -4894,7 +4894,7 @@ This function sets up the following dynamically scoped 
variables:
                        (push (cons field v) org-table-local-parameters)
                        (push (list field line col)
                              org-table-named-field-locations))))))))))
-      ;; Re-use existing markers when possible.
+      ;; Reuse existing markers when possible.
       (if (markerp org-table-current-begin-pos)
          (move-marker org-table-current-begin-pos (point))
        (setq org-table-current-begin-pos (point-marker)))
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el
index e5b0fbcf2a9..8eebdbe09b2 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.11"))
+   (let ((org-release "9.6.13"))
      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.11"))
+   (let ((org-git-version "release_9.6.13"))
      org-git-version))
 
 (provide 'org-version)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index 34c572a3f57..d1f63762e50 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.11
+;; Version: 9.6.13
 
 ;; This file is part of GNU Emacs.
 ;;
@@ -1230,7 +1230,7 @@ This applies to indirect buffers created with the commands
 Valid values are:
 current-window   Display in the current window
 other-window     Just display in another window.
-dedicated-frame  Create one new frame, and re-use it each time.
+dedicated-frame  Create one new frame, and reuse it each time.
 new-frame        Make a new frame each time.  Note that in this case
                  previously-made indirect buffers are kept, and you need to
                  kill these buffers yourself."
@@ -4582,7 +4582,7 @@ is available.  This option applies only if FILE is a URL."
                            file)
                   nil))
             (error (if noerror
-                       (message "Org could't download \"%s\": %s %S" file (car 
error) (cdr error))
+                       (message "Org couldn't download \"%s\": %s %S" file 
(car error) (cdr error))
                      (signal (car error) (cdr error)))))
         (funcall (if noerror #'message #'user-error)
                  "The remote resource %S is considered unsafe, and will not be 
downloaded."
@@ -19985,7 +19985,7 @@ With argument N not nil or 1, move forward N - 1 lines 
first."
        (if (eq special 'reversed)
            (when (and (= origin bol) (eq last-command this-command))
              (goto-char refpos))
-         (when (or (> origin refpos) (= origin bol))
+         (when (or (> origin refpos) (<= origin bol))
            (goto-char refpos)))))
      ((and (looking-at org-list-full-item-re)
           (memq (org-element-type (save-match-data (org-element-at-point)))
@@ -20000,7 +20000,7 @@ With argument N not nil or 1, move forward N - 1 lines 
first."
        (if (eq special 'reversed)
            (when (and (= (point) origin) (eq last-command this-command))
              (goto-char after-bullet))
-         (when (or (> origin after-bullet) (= (point) origin))
+         (when (or (> origin after-bullet) (>= (point) origin))
            (goto-char after-bullet)))))
      ;; No special context.  Point is already at beginning of line.
      (t nil))))
@@ -20055,7 +20055,7 @@ With argument N not nil or 1, move forward N - 1 lines 
first."
                   (goto-char tags)
                 (end-of-line)))
              (t
-              (if (or (< origin tags) (= origin (line-end-position)))
+              (if (or (< origin tags) (>= origin (line-end-position)))
                   (goto-char tags)
                 (end-of-line))))))
      ((bound-and-true-p visual-line-mode)
diff --git a/lisp/org/ox-beamer.el b/lisp/org/ox-beamer.el
index 2590bd5fa72..10a2c803a00 100644
--- a/lisp/org/ox-beamer.el
+++ b/lisp/org/ox-beamer.el
@@ -929,7 +929,7 @@ holding export options."
  '((":\\(B_[a-z]+\\|BMCOL\\):" 1 'org-beamer-tag prepend))
  'prepend)
 
-(defface org-beamer-tag '((t (:box (:line-width 1 :color grey40))))
+(defface org-beamer-tag '((t (:box (:line-width 1 :color "grey40"))))
   "The special face for beamer tags."
   :group 'org-export-beamer)
 
diff --git a/lisp/progmodes/asm-mode.el b/lisp/progmodes/asm-mode.el
index 0f5af9803a5..efe9982feab 100644
--- a/lisp/progmodes/asm-mode.el
+++ b/lisp/progmodes/asm-mode.el
@@ -1,6 +1,6 @@
 ;;; asm-mode.el --- mode for editing assembler code  -*- lexical-binding: t; 
-*-
 
-;; Copyright (C) 1991, 2001-2023 Free Software Foundation, Inc.
+;; Copyright (C) 1991-2023 Free Software Foundation, Inc.
 
 ;; Author: Eric S. Raymond <esr@thyrsus.com>
 ;; Maintainer: emacs-devel@gnu.org
@@ -52,9 +52,13 @@
   :link '(custom-group-link :tag "Font Lock Faces group" font-lock-faces)
   :group 'languages)
 
+(defun asm--safe-comment-char-p (char)
+  (memq char '(?\; ?# ?@)))
+
 (defcustom asm-comment-char ?\;
   "The `comment-start' character assumed by Asm mode."
-  :type 'character)
+  :type 'character
+  :safe #'asm--safe-comment-char-p)
 
 (defvar asm-mode-syntax-table
   (let ((st (make-syntax-table)))
diff --git a/lisp/progmodes/c-ts-common.el b/lisp/progmodes/c-ts-common.el
index 3b0814970ad..eba13934ede 100644
--- a/lisp/progmodes/c-ts-common.el
+++ b/lisp/progmodes/c-ts-common.el
@@ -116,7 +116,7 @@ non-whitespace characters of the current line."
   "Regexp pattern that matches a comment in C-like languages.")
 
 (defun c-ts-common--fill-paragraph (&optional arg)
-  "Fillling function for `c-ts-common'.
+  "Filling function for `c-ts-common'.
 ARG is passed to `fill-paragraph'."
   (interactive "*P")
   (save-restriction
@@ -134,7 +134,7 @@ ARG is passed to `fill-paragraph'."
       t)))
 
 (defun c-ts-common--fill-block-comment (&optional arg)
-  "Fillling function for block comments.
+  "Filling function for block comments.
 ARG is passed to `fill-paragraph'.  Assume point is in a block
 comment."
   (let* ((node (treesit-node-at (point)))
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 51f60f70131..94c1d9ac654 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -322,7 +322,8 @@ PARENT and BOL are like other anchor functions."
                                (treesit-node-parent prev-sibling) t)))
           ;; If the start of the previous sibling isn't at the
           ;; beginning of a line, something's probably not quite
-          ;; right, go a step further.
+          ;; right, go a step further. (E.g., comment after a
+          ;; statement.)
           (_ (goto-char (treesit-node-start prev-sibling))
              (if (looking-back (rx bol (* whitespace))
                                (line-beginning-position))
@@ -356,27 +357,40 @@ PARENT, BOL, ARGS are the same as other anchor functions."
   (apply (alist-get 'standalone-parent treesit-simple-indent-presets)
          parent (treesit-node-parent parent) bol args))
 
-(defun c-ts-mode--prev-line-match (regexp)
-  "An indentation matcher that matches if previous line matches REGEXP."
-  (lambda (_n _p bol &rest _)
-    (save-excursion
-      (goto-char bol)
-      (forward-line -1)
-      (back-to-indentation)
-      (looking-at-p regexp))))
+(defun c-ts-mode--else-heuristic (node parent bol &rest _)
+  "Heuristic matcher for when \"else\" is followed by a closing bracket.
+NODE, PARENT, and BOL are the same as in other matchers."
+  (and (null node)
+       (save-excursion
+         (forward-line -1)
+         (looking-at (rx (* whitespace) "else" (* whitespace) eol)))
+       (let ((next-node (treesit-node-first-child-for-pos parent bol)))
+         (equal (treesit-node-type next-node) "}"))))
+
+(defun c-ts-mode--first-sibling (node parent &rest _)
+  "Matches when NODE is the \"first sibling\".
+\"First sibling\" is defined as: the first child node of PARENT
+such that it's on its own line.  NODE is the node to match and
+PARENT is its parent."
+  (let ((prev-sibling (treesit-node-prev-sibling node t)))
+    (or (null prev-sibling)
+        (save-excursion
+          (goto-char (treesit-node-start prev-sibling))
+          (<= (line-beginning-position)
+              (treesit-node-start parent)
+              (line-end-position))))))
 
 (defun c-ts-mode--indent-styles (mode)
   "Indent rules supported by `c-ts-mode'.
 MODE is either `c' or `cpp'."
   (let ((common
          `((c-ts-mode--for-each-tail-body-matcher prev-line 
c-ts-mode-indent-offset)
-           ;; If the user types "if (...)" and hits RET, they expect
-           ;; point on the empty line to be indented; this rule
-           ;; does that.
-           ((and no-node
-                 (c-ts-mode--prev-line-match
-                  ,(rx (or "if" "else" "while" "do" "for"))))
-            prev-line c-ts-mode-indent-offset)
+           ;; If the user types "else" and hits RET, they expect point
+           ;; on the empty line to be indented; this rule does that.
+           ;; This heuristic is intentionally very specific because
+           ;; more general heuristic is very error-prone, see
+           ;; discussion in bug#67417.
+           (c-ts-mode--else-heuristic prev-line c-ts-mode-indent-offset)
 
            ((parent-is "translation_unit") column-0 0)
            ((query "(ERROR (ERROR)) @indent") column-0 0)
@@ -423,6 +437,8 @@ MODE is either `c' or `cpp'."
            ((parent-is "preproc") c-ts-mode--anchor-prev-sibling 0)
 
            ((parent-is "function_definition") parent-bol 0)
+           ((parent-is "pointer_declarator") parent-bol 0)
+           ((parent-is "declaration") parent-bol 0)
            ((parent-is "conditional_expression") first-sibling 0)
            ((parent-is "assignment_expression") parent-bol 
c-ts-mode-indent-offset)
            ((parent-is "concatenated_string") first-sibling 0)
@@ -458,7 +474,11 @@ MODE is either `c' or `cpp'."
            ((parent-is "field_declaration_list") 
c-ts-mode--anchor-prev-sibling 0)
 
            ;; Statement in {} blocks.
-           ((or (match nil "compound_statement" nil 1 1)
+           ((or (and (parent-is "compound_statement")
+                     ;; If the previous sibling(s) are not on their
+                     ;; own line, indent as if this node is the first
+                     ;; sibling (Bug#67357)
+                     c-ts-mode--first-sibling)
                 (match null "compound_statement"))
             standalone-parent c-ts-mode-indent-offset)
            ((parent-is "compound_statement") c-ts-mode--anchor-prev-sibling 0)
@@ -471,6 +491,7 @@ MODE is either `c' or `cpp'."
            ((parent-is "if_statement") standalone-parent 
c-ts-mode-indent-offset)
            ((parent-is "else_clause") standalone-parent 
c-ts-mode-indent-offset)
            ((parent-is "for_statement") standalone-parent 
c-ts-mode-indent-offset)
+           ((match "while" "do_statement") parent-bol 0) ; (do_statement 
"while")
            ((parent-is "while_statement") standalone-parent 
c-ts-mode-indent-offset)
            ((parent-is "do_statement") standalone-parent 
c-ts-mode-indent-offset)
 
@@ -495,13 +516,13 @@ MODE is either `c' or `cpp'."
        ((node-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
        ((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
        ((parent-is "compound_statement") parent-bol c-ts-mode-indent-offset)
-       ((parent-is "if_statement") parent-bol 0)
-       ((parent-is "else_clause") parent-bol 0)
-       ((parent-is "for_statement") parent-bol 0)
-       ((parent-is "while_statement") parent-bol 0)
-       ((parent-is "switch_statement") parent-bol 0)
-       ((parent-is "case_statement") parent-bol 0)
-       ((parent-is "do_statement") parent-bol 0)
+       ((match "compound_statement" "if_statement") standalone-parent 0)
+       ((match "compound_statement" "else_clause") standalone-parent 0)
+       ((match "compound_statement" "for_statement") standalone-parent 0)
+       ((match "compound_statement" "while_statement") standalone-parent 0)
+       ((match "compound_statement" "switch_statement") standalone-parent 0)
+       ((match "compound_statement" "case_statement") standalone-parent 0)
+       ((match "compound_statement" "do_statement") standalone-parent 0)
        ,@common))))
 
 (defun c-ts-mode--top-level-label-matcher (node parent &rest _)
@@ -1362,7 +1383,7 @@ recommended to enable `electric-pair-mode' with this 
mode."
                                                 c-ts-mode-indent-style)
       :help "Show the name of the C/C++ indentation style for current buffer"]
      ["Set Comment Style" c-ts-mode-toggle-comment-style
-      :help "Toglle C/C++ comment style between block and line comments"])
+      :help "Toggle C/C++ comment style between block and line comments"])
     "--"
     ("Toggle..."
      ["SubWord Mode" subword-mode
diff --git a/lisp/progmodes/cc-engine.el b/lisp/progmodes/cc-engine.el
index 018a194ac14..6154253e6b3 100644
--- a/lisp/progmodes/cc-engine.el
+++ b/lisp/progmodes/cc-engine.el
@@ -7554,7 +7554,7 @@ multi-line strings (but not C++, for example)."
 (defun c-ml-string-opener-intersects-region (&optional start finish)
   ;; If any part of the region [START FINISH] is inside an ml-string opener,
   ;; return a dotted list of the start, end and double-quote position of the
-  ;; first such opener.  That list wlll not include any "context characters"
+  ;; first such opener.  That list will not include any "context characters"
   ;; before or after the opener.  If an opener is found, the match-data will
   ;; indicate it, with (match-string 1) being the entire delimiter, and
   ;; (match-string 2) the "main" double-quote.  Otherwise, the match-data is
@@ -9891,7 +9891,7 @@ point unchanged and return nil."
   ;; Note that this function is incomplete, handling only those cases expected
   ;; to be common in a C++20 requires clause.
   ;;
-  ;; Note also that (...) is not recognised as a primary expression if the
+  ;; Note also that (...) is not recognized as a primary expression if the
   ;; next token is an open brace.
   (let ((here (point))
        (c-restricted-<>-arglists t)
@@ -13021,7 +13021,7 @@ comment at the start of cc-engine.el for more info."
 
 (defun c-laomib-get-cache (containing-sexp start)
   ;; Get an element from `c-laomib-cache' matching CONTAINING-SEXP, and which
-  ;; is suitable for start postiion START.
+  ;; is suitable for start position START.
   ;; Return that element or nil if one wasn't found.
   (let ((ptr c-laomib-cache)
        elt)
diff --git a/lisp/progmodes/cc-mode.el b/lisp/progmodes/cc-mode.el
index 227a6af2a6b..4842de15164 100644
--- a/lisp/progmodes/cc-mode.el
+++ b/lisp/progmodes/cc-mode.el
@@ -256,6 +256,9 @@ control).  See \"cc-mode.el\" for more info."
        (put 'c-initialize-cc-mode initprop c-initialization-ok))))
 
   ;; Set up text conversion, for Emacs >= 30.0
+  ;; This is needed here because CC-mode's implementation of
+  ;; electricity does not rely on `post-self-insert-hook' (which is
+  ;; already handled adequately by `analyze-text-conversion').
   (when (boundp 'post-text-conversion-hook)
     (add-hook 'post-text-conversion-hook #'c-post-text-conversion nil t))
 
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index 9e441dbfcf7..5522c1afc55 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -1789,7 +1789,7 @@ to a function that generates a unique name."
 ;; run compile with the default command line
 (defun recompile (&optional edit-command)
   "Re-compile the program including the current buffer.
-If this is run in a Compilation mode buffer, re-use the arguments from the
+If this is run in a Compilation mode buffer, reuse the arguments from the
 original use.  Otherwise, recompile using `compile-command'.
 If the optional argument `edit-command' is non-nil, the command can be edited."
   (interactive "P")
diff --git a/lisp/progmodes/cperl-mode.el b/lisp/progmodes/cperl-mode.el
index ab624a08646..58cf2728f61 100644
--- a/lisp/progmodes/cperl-mode.el
+++ b/lisp/progmodes/cperl-mode.el
@@ -1463,7 +1463,7 @@ function tests that property."
 
 (defun cperl-block-declaration-p ()
   "Test whether the following ?\\{ opens a declaration block.
-Returns the column where the declarating keyword is found, or nil
+Returns the column where the declaring keyword is found, or nil
 if this isn't a declaration block.  Declaration blocks are named
 subroutines, packages and the like.  They start with a keyword
 and a name, to be followed by various descriptive items which are
@@ -4206,7 +4206,7 @@ recursive calls in starting lines of here-documents."
                    (setq tmpend tb))
                (put-text-property b (point) 'syntax-type 'format))
               ;; quotelike operator or regexp: capture groups 10 or 11
-               ;; matches some false postives, to be eliminated here
+               ;; matches some false positives, to be eliminated here
               ((or (match-beginning 10) (match-beginning 11))
                (setq b1 (if (match-beginning 10) 10 11)
                      argument (buffer-substring
@@ -5877,7 +5877,7 @@ functions (which they are not).  Inherits from 
`default'.")
                                              (eval cperl--ws*-rx))
                                    ;; ... or the start of a "sloppy" signature
                                    (sequence (eval cperl--sloppy-signature-rx)
-                                             ;; arbtrarily continue "a few 
lines"
+                                             ;; arbitrarily continue "a few 
lines"
                                              (repeat 0 200 (not (in "{"))))
                                    ;; make sure we have a reasonably
                                    ;; short match for an incomplete sub
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index d410367f902..6e43cc2b01c 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -216,7 +216,7 @@ chosen (interactively or automatically)."
                                 (vimrc-mode . ("vim-language-server" 
"--stdio"))
                                 ((python-mode python-ts-mode)
                                  . ,(eglot-alternatives
-                                     '("pylsp" "pyls" ("pyright-langserver" 
"--stdio") "jedi-language-server")))
+                                     '("pylsp" "pyls" ("pyright-langserver" 
"--stdio") "jedi-language-server" "ruff-lsp")))
                                 ((js-json-mode json-mode json-ts-mode)
                                  . ,(eglot-alternatives 
'(("vscode-json-language-server" "--stdio")
                                                           
("vscode-json-languageserver" "--stdio")
@@ -1011,10 +1011,7 @@ ACTION is an LSP object of either `CodeAction' or 
`Command' type."
     :accessor eglot--managed-buffers)
    (saved-initargs
     :documentation "Saved initargs for reconnection purposes."
-    :accessor eglot--saved-initargs)
-   (inferior-process
-    :documentation "Server subprocess started automatically."
-    :accessor eglot--inferior-process))
+    :accessor eglot--saved-initargs))
   :documentation
   "Represents a server. Wraps a process for LSP communication.")
 
@@ -1151,9 +1148,6 @@ PRESERVE-BUFFERS as in `eglot-shutdown', which see."
   (maphash (lambda (_dir watch-and-ids)
              (file-notify-rm-watch (car watch-and-ids)))
            (eglot--file-watches server))
-  ;; Kill any autostarted inferior processes
-  (when-let (proc (eglot--inferior-process server))
-    (delete-process proc))
   ;; Sever the project/server relationship for `server'
   (setf (gethash (eglot--project server) eglot--servers-by-project)
         (delq server
@@ -1280,14 +1274,18 @@ be guessed."
                          (concat "`%s' not found in PATH, but can't form"
                                  " an interactive prompt for to fix %s!")
                          program guess))))))
+         (input (and prompt (read-shell-command prompt
+                                                full-program-invocation
+                                                'eglot-command-history)))
          (contact
-          (or (and prompt
-                   (split-string-and-unquote
-                    (read-shell-command
-                     prompt
-                     full-program-invocation
-                     'eglot-command-history)))
-              guess)))
+          (if input
+              (if (string-match
+                   "^[\s\t]*\\(.*\\):\\([[:digit:]]+\\)[\s\t]*$" input)
+                  ;; <host>:<port> special case (bug#67682)
+                  (list (match-string 1 input)
+                        (string-to-number (match-string 2 input)))
+                (split-string-and-unquote input))
+            guess)))
     (list managed-modes (eglot--current-project) class contact language-ids)))
 
 (defvar eglot-lsp-context)
@@ -1460,7 +1458,6 @@ This docstring appeases checkdoc, that's all."
   (let* ((default-directory (project-root project))
          (nickname (project-name project))
          (readable-name (format "EGLOT (%s/%s)" nickname managed-modes))
-         autostart-inferior-process
          server-info
          (contact (if (functionp contact) (funcall contact) contact))
          (initargs
@@ -1473,16 +1470,16 @@ This docstring appeases checkdoc, that's all."
                                       readable-name nil
                                       (car contact) (cadr contact)
                                       (cddr contact)))))
-                ((and (stringp (car contact)) (memq :autoport contact))
+                ((and (stringp (car contact))
+                      (cl-find-if (lambda (x)
+                                    (or (eq x :autoport)
+                                        (eq (car-safe x) :autoport)))
+                                  contact))
                  (setq server-info (list "<inferior process>"))
-                 `(:process ,(lambda ()
-                               (pcase-let ((`(,connection . ,inferior)
-                                            (eglot--inferior-bootstrap
+                 `(:process ,(jsonrpc-autoport-bootstrap
                                              readable-name
                                              contact
-                                             '(:noquery t))))
-                                 (setq autostart-inferior-process inferior)
-                                 connection))))
+                                             :connect-args '(:noquery t))))
                 ((stringp (car contact))
                  (let* ((probe (cl-position-if #'keywordp contact))
                         (more-initargs (and probe (cl-subseq contact probe)))
@@ -1531,7 +1528,6 @@ This docstring appeases checkdoc, that's all."
     (setf (eglot--languages server)
           (cl-loop for m in managed-modes for l in language-ids
                    collect (cons m l)))
-    (setf (eglot--inferior-process server) autostart-inferior-process)
     (run-hook-with-args 'eglot-server-initialized-hook server)
     ;; Now start the handshake.  To honor `eglot-sync-connect'
     ;; maybe-sync-maybe-async semantics we use `jsonrpc-async-request'
@@ -1624,55 +1620,6 @@ in project `%s'."
           (quit (jsonrpc-shutdown server) (setq canceled 'quit)))
       (setq tag nil))))
 
-(defun eglot--inferior-bootstrap (name contact &optional connect-args)
-  "Use CONTACT to start a server, then connect to it.
-Return a cons of two process objects (CONNECTION . INFERIOR).
-Name both based on NAME.
-CONNECT-ARGS are passed as additional arguments to
-`open-network-stream'."
-  (let* ((port-probe (make-network-process :name "eglot-port-probe-dummy"
-                                           :server t
-                                           :host "localhost"
-                                           :service 0))
-         (port-number (unwind-protect
-                          (process-contact port-probe :service)
-                        (delete-process port-probe)))
-         inferior connection)
-    (unwind-protect
-        (progn
-          (setq inferior
-                (make-process
-                 :name (format "autostart-inferior-%s" name)
-                 :stderr (format "*%s stderr*" name)
-                 :noquery t
-                 :command (cl-subst
-                           (format "%s" port-number) :autoport contact)))
-          (setq connection
-                (cl-loop
-                 repeat 10 for i from 1
-                 do (accept-process-output nil 0.5)
-                 while (process-live-p inferior)
-                 do (eglot--message
-                     "Trying to connect to localhost and port %s (attempt %s)"
-                     port-number i)
-                 thereis (ignore-errors
-                           (apply #'open-network-stream
-                                  (format "autoconnect-%s" name)
-                                  nil
-                                  "localhost" port-number connect-args))))
-          (cons connection inferior))
-      (cond ((and (process-live-p connection)
-                  (process-live-p inferior))
-             (eglot--message "Done, connected to %s!" port-number))
-            (t
-             (when inferior (delete-process inferior))
-             (when connection (delete-process connection))
-             (eglot--error "Could not start and connect to server%s"
-                           (if inferior
-                               (format " started with %s"
-                                       (process-command inferior))
-                             "!")))))))
-
 
 ;;; Helpers (move these to API?)
 ;;;
@@ -2030,13 +1977,15 @@ Use `eglot-managed-p' to determine if current buffer is 
managed.")
   "Return logical Eglot server for current buffer, nil if none."
   (setq eglot--cached-server
         (or eglot--cached-server
-            (cl-find-if #'eglot--languageId
-                        (gethash (eglot--current-project)
-                                 eglot--servers-by-project))
-            (and eglot-extend-to-xref
-                 buffer-file-name
-                 (gethash (expand-file-name buffer-file-name)
-                          eglot--servers-by-xrefed-file)))))
+            (and (not (eq major-mode 'fundamental-mode)) ; gh#1330
+                 (or
+                  (cl-find-if #'eglot--languageId
+                              (gethash (eglot--current-project)
+                                       eglot--servers-by-project))
+                  (and eglot-extend-to-xref
+                       buffer-file-name
+                       (gethash (expand-file-name buffer-file-name)
+                                eglot--servers-by-xrefed-file)))))))
 
 (defun eglot--current-server-or-lose ()
   "Return current logical Eglot server connection or error."
diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el
index 70af736372e..0f0bb73ae77 100644
--- a/lisp/progmodes/gud.el
+++ b/lisp/progmodes/gud.el
@@ -3974,11 +3974,11 @@ def gud_complete(s, max):
         print(f'\"{string_list.GetStringAtIndex(i)}\" ')
     print(')##')
 "
-  "Python code sent to LLDB for gud-specific initialisation.")
+  "Python code sent to LLDB for gud-specific initialization.")
 
 (defun gud-lldb-fetch-completions (context command)
   "Return the data to complete the LLDB command before point.
-This is what the Python function we installed at initialzation
+This is what the Python function we installed at initialization
 time returns, as a Lisp list.
 Maximum number of completions requested from LLDB is controlled
 by `gud-lldb-max-completions', which see."
@@ -4057,7 +4057,7 @@ Please note that completion framework that complete while 
you
 type, like Corfu, do not work well with this mode.  You should
 consider to turn them off in this mode.
 
-This command runs functions from `lldb-mode-hook'. "
+This command runs functions from `lldb-mode-hook'."
   (interactive (list (gud-query-cmdline 'lldb)))
 
   (when (and gud-comint-buffer
diff --git a/lisp/progmodes/hideif.el b/lisp/progmodes/hideif.el
index 836db83c2f3..e913d37371a 100644
--- a/lisp/progmodes/hideif.el
+++ b/lisp/progmodes/hideif.el
@@ -1801,7 +1801,7 @@ and `+='...)."
                    actual-parms nil)))
 
           (t
-           (error "Interal error: impossible case."))))
+           (error "Internal error: impossible case"))))
 
        (pop actual-parms)
        while actual-parms) ; end cl-loop
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 5a669fdbd42..61bd94222ac 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -3463,6 +3463,11 @@ Check if a node type is available, then return the right 
indent rules."
        ((parent-is "class_body") parent-bol js-indent-level)
        ((parent-is ,switch-case) parent-bol js-indent-level)
        ((parent-is "statement_block") parent-bol js-indent-level)
+       ((match "while" "do_statement") parent-bol 0)
+       ((match "else" "if_statement") parent-bol 0)
+       ((parent-is ,(rx (or (seq (or "if" "for" "for_in" "while" "do") 
"_statement")
+                            "else_clause")))
+        parent-bol js-indent-level)
 
        ;; JSX
        ,@(js-jsx--treesit-indent-compatibility-bb1f97b)
@@ -3497,7 +3502,7 @@ Check if a node type is available, then return the right 
indent rules."
 
    :language 'javascript
    :feature 'comment
-   '((comment) @font-lock-comment-face)
+   '([(comment) (hash_bang_line)] @font-lock-comment-face)
 
    :language 'javascript
    :feature 'constant
@@ -3536,14 +3541,10 @@ Check if a node type is available, then return the 
right indent rules."
      (method_definition
       name: (property_identifier) @font-lock-function-name-face)
 
-     (method_definition
-      parameters: (formal_parameters (identifier) 
@font-lock-variable-name-face))
-
-     (arrow_function
-      parameters: (formal_parameters (identifier) 
@font-lock-variable-name-face))
-
-     (function_declaration
-      parameters: (formal_parameters (identifier) 
@font-lock-variable-name-face))
+     (formal_parameters
+      [(identifier) @font-lock-variable-name-face
+       (array_pattern (identifier) @font-lock-variable-name-face)
+       (object_pattern (shorthand_property_identifier_pattern) 
@font-lock-variable-name-face)])
 
      (variable_declarator
       name: (identifier) @font-lock-variable-name-face)
@@ -3570,16 +3571,6 @@ Check if a node type is available, then return the right 
indent rules."
      ;; full namespace import (* as alias)
      (import_clause (namespace_import (identifier) 
@font-lock-variable-name-face)))
 
-   :language 'javascript
-   :feature 'property
-   '(((property_identifier) @font-lock-property-use-face
-      (:pred js--treesit-property-not-function-p
-             @font-lock-property-use-face))
-
-     (pair value: (identifier) @font-lock-variable-use-face)
-
-     ((shorthand_property_identifier) @font-lock-property-use-face))
-
    :language 'javascript
    :feature 'assignment
    '((assignment_expression
@@ -3591,13 +3582,7 @@ Check if a node type is available, then return the right 
indent rules."
       function: [(identifier) @font-lock-function-call-face
                  (member_expression
                   property:
-                  (property_identifier) @font-lock-function-call-face)])
-     (method_definition
-      name: (property_identifier) @font-lock-function-name-face)
-     (function_declaration
-      name: (identifier) @font-lock-function-call-face)
-     (function
-      name: (identifier) @font-lock-function-name-face))
+                  (property_identifier) @font-lock-function-call-face)]))
 
    :language 'javascript
    :feature 'jsx
@@ -3606,6 +3591,12 @@ Check if a node type is available, then return the right 
indent rules."
      (jsx_self_closing_element name: (_) @font-lock-function-call-face)
      (jsx_attribute (property_identifier) @font-lock-constant-face))
 
+   :language 'javascript
+   :feature 'property
+   '(((property_identifier) @font-lock-property-use-face)
+     (pair value: (identifier) @font-lock-variable-use-face)
+     ((shorthand_property_identifier) @font-lock-property-use-face))
+
    :language 'javascript
    :feature 'number
    '((number) @font-lock-number-face
@@ -3657,18 +3648,11 @@ OVERRIDE is the override flag described in
       (setq font-beg (treesit-node-end child)
             child (treesit-node-next-sibling child)))))
 
-(defun js--treesit-property-not-function-p (node)
-  "Check that NODE, a property_identifier, is not used as a function."
-  (not (equal (treesit-node-type
-               (treesit-node-parent ; Maybe call_expression.
-                (treesit-node-parent ; Maybe member_expression.
-                 node)))
-              "call_expression")))
-
 (defvar js--treesit-lhs-identifier-query
   (when (treesit-available-p)
     (treesit-query-compile 'javascript '((identifier) @id
-                                         (property_identifier) @id)))
+                                         (property_identifier) @id
+                                         
(shorthand_property_identifier_pattern) @id)))
   "Query that captures identifier and query_identifier.")
 
 (defun js--treesit-fontify-assignment-lhs (node override start end &rest _)
@@ -3680,7 +3664,8 @@ For OVERRIDE, START, END, see `treesit-font-lock-rules'."
      (treesit-node-start node) (treesit-node-end node)
      (pcase (treesit-node-type node)
        ("identifier" 'font-lock-variable-use-face)
-       ("property_identifier" 'font-lock-property-use-face))
+       ("property_identifier" 'font-lock-property-use-face)
+       ("shorthand_property_identifier_pattern" 'font-lock-variable-use-face))
      override start end)))
 
 (defun js--treesit-defun-name (node)
diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el
index 7307a5b13f1..cbf0e573e37 100644
--- a/lisp/progmodes/lua-ts-mode.el
+++ b/lisp/progmodes/lua-ts-mode.el
@@ -552,7 +552,6 @@ Calls REPORT-FN directly."
     (with-current-buffer lua-ts-inferior-buffer
       (setq-local comint-input-ignoredups t
                   comint-input-ring-file-name lua-ts-inferior-history
-                  comint-use-prompt-regexp t
                   comint-prompt-read-only t
                   comint-prompt-regexp (rx-to-string `(: bol
                                                          
,lua-ts-inferior-prompt
@@ -560,9 +559,7 @@ Calls REPORT-FN directly."
       (comint-read-input-ring t)
       (add-hook 'comint-preoutput-filter-functions
                 (lambda (string)
-                  (if (or (not (equal (buffer-name) lua-ts-inferior-buffer))
-                          (equal string
-                                 (concat lua-ts-inferior-prompt-continue " ")))
+                  (if (equal string (concat lua-ts-inferior-prompt-continue " 
"))
                       string
                     (concat
                      ;; Filter out the extra prompt characters that
@@ -576,7 +573,8 @@ Calls REPORT-FN directly."
                                                     (group (* nonl))))
                                                "\\1" string)
                      ;; Re-add the prompt for the next line.
-                     lua-ts-inferior-prompt " "))))))
+                     lua-ts-inferior-prompt " ")))
+                nil t)))
   (select-window (display-buffer lua-ts-inferior-buffer
                                  '((display-buffer-reuse-window
                                     display-buffer-pop-up-frame)
diff --git a/lisp/progmodes/perl-mode.el b/lisp/progmodes/perl-mode.el
index b8d811baf0d..16dfe0b4dd2 100644
--- a/lisp/progmodes/perl-mode.el
+++ b/lisp/progmodes/perl-mode.el
@@ -468,7 +468,7 @@
                      (scan-error (goto-char startpos) nil))
                  (not (or (nth 8 (parse-partial-sexp
                                   ;; Since we don't know if point is within
-                                  ;; the first or the scond arg, we have to
+                                  ;; the first or the second arg, we have to
                                   ;; start from the beginning.
                                   (if twoargs (1+ (nth 8 state)) (point))
                                   limit nil nil state 'syntax-table))
@@ -514,7 +514,7 @@
                                     (string-to-syntax "|e")
                                   (string-to-syntax "\"e")))
              (forward-char 1)
-             ;; Re-use perl-syntax-propertize-special-constructs to handle the
+             ;; Reuse perl-syntax-propertize-special-constructs to handle the
              ;; second part (the first delimiter of second part can't be
              ;; preceded by "s" or "tr" or "y", so it will not be considered
              ;; as twoarg).
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index a81bb63fba4..0fa623616b6 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1841,10 +1841,12 @@ It's also possible to enter an arbitrary directory not 
in the list."
 ;;;###autoload
 (defun project-any-command (&optional overriding-map prompt-format)
   "Run the next command in the current project.
-If the command is in `project-prefix-map', it gets passed that
-info with `project-current-directory-override'.  Otherwise,
-`default-directory' is temporarily set to the current project's
-root.
+
+If the command name starts with `project-', or its symbol has
+property `project-aware', it gets passed the project to use
+with the variable `project-current-directory-override'.
+Otherwise, `default-directory' is temporarily set to the current
+project's root.
 
 If OVERRIDING-MAP is non-nil, it will be used as
 `overriding-local-map' to provide shorter bindings from that map
@@ -1856,15 +1858,11 @@ which will take priority over the global ones."
                     (key-binding (read-key-sequence
                                   (format prompt-format (project-root pr)))
                                  t)))
-         (root (project-root pr))
-         found)
+         (root (project-root pr)))
     (when command
-      ;; We could also check the command name against "\\`project-",
-      ;; and/or (get command 'project-command).
-      (map-keymap
-       (lambda (_evt cmd) (if (eq cmd command) (setq found t)))
-       project-prefix-map)
-      (if found
+      (if (when (symbolp command)
+            (or (string-prefix-p "project-" (symbol-name command))
+                (get command 'project-aware)))
           (let ((project-current-directory-override root))
             (call-interactively command))
         (let ((default-directory root))
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ab3bf1b4ec0..211969140ab 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -1124,7 +1124,8 @@ fontified."
       name: (identifier) @font-lock-function-name-face)
      (class_definition
       name: (identifier) @font-lock-type-face)
-     (parameters (identifier) @font-lock-variable-name-face))
+     (parameters (identifier) @font-lock-variable-name-face)
+     (parameters (default_parameter name: (identifier) 
@font-lock-variable-name-face)))
 
    :feature 'function
    :language 'python
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 5c34ddc562b..bca86a57c7d 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -2106,12 +2106,6 @@ or `gem' statement around point."
     "\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
     "Regexp to match the beginning of percent literal.")
 
-  (defconst ruby-syntax-methods-before-regexp
-    '("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
-      "assert_match" "Given" "Then" "When")
-    "Methods that can take regexp as the first argument.
-It will be properly highlighted even when the call omits parens.")
-
   (defvar ruby-syntax-before-regexp-re
     (concat
      ;; Special tokens that can't be followed by a division operator.
@@ -2123,11 +2117,9 @@ It will be properly highlighted even when the call omits 
parens.")
      "\\|\\(?:^\\|\\s \\)"
      (regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
                    "or" "not" "&&" "||"))
-     ;; Method name from the list.
-     "\\|\\_<"
-     (regexp-opt ruby-syntax-methods-before-regexp)
      "\\)\\s *")
-    "Regexp to match text that can be followed by a regular expression."))
+    "Regexp to match text that disambiguates a regular expression.
+A slash character after any of these should begin a regexp."))
 
 (defun ruby-syntax-propertize (start end)
   "Syntactic keywords for Ruby mode.  See `syntax-propertize-function'."
@@ -2187,10 +2179,14 @@ It will be properly highlighted even when the call 
omits parens.")
             (when (or
                    ;; Beginning of a regexp.
                    (and (null (nth 8 state))
-                        (save-excursion
-                          (forward-char -1)
-                          (looking-back ruby-syntax-before-regexp-re
-                                        (line-beginning-position))))
+                        (or (not
+                             ;; Looks like division.
+                             (or (eql (char-after) ?\s)
+                                 (not (eql (char-before (1- (point))) ?\s))))
+                            (save-excursion
+                              (forward-char -1)
+                              (looking-back ruby-syntax-before-regexp-re
+                                            (line-beginning-position)))))
                    ;; End of regexp.  We don't match the whole
                    ;; regexp at once because it can have
                    ;; string interpolation inside, or span
diff --git a/lisp/progmodes/ruby-ts-mode.el b/lisp/progmodes/ruby-ts-mode.el
index b339e2028ab..284880a0a36 100644
--- a/lisp/progmodes/ruby-ts-mode.el
+++ b/lisp/progmodes/ruby-ts-mode.el
@@ -601,7 +601,7 @@ a statement container is a node that matches
 
            ;; case expression: when, in_clause, and else are all
            ;; children of case.  when and in_clause have pattern and
-           ;; body as fields.  body has "then" and then the statemets.
+           ;; body as fields.  body has "then" and then the statements.
            ;; i.e. the statements are not children of when but then.
            ;; But for the statements are children of else.
            ((match "when" "case")
diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el
index 03ff2776d3a..ac860969daf 100644
--- a/lisp/progmodes/rust-ts-mode.el
+++ b/lisp/progmodes/rust-ts-mode.el
@@ -296,13 +296,13 @@
 (defun rust-ts-mode--comment-docstring (node override start end &rest _args)
   "Use the comment or documentation face appropriately for comments."
   (let* ((beg (treesit-node-start node))
-         (end (treesit-node-end node))
          (face (save-excursion
                  (goto-char beg)
-                 (if (looking-at "///")
+                 (if (looking-at 
"/\\(?:/\\(?:/[^/]\\|!\\)\\|*\\(?:*[^*/]\\|!\\)\\)" t)
                      'font-lock-doc-face
                    'font-lock-comment-face))))
-    (treesit-fontify-with-override beg end face override start end)))
+    (treesit-fontify-with-override beg (treesit-node-end node)
+                                   face override start end)))
 
 (defun rust-ts-mode--fontify-scope (node override start end &optional tail-p)
   (let* ((case-fold-search nil)
@@ -459,6 +459,10 @@ See `prettify-symbols-compose-predicate'."
     (setq-local indent-tabs-mode nil
                 treesit-simple-indent-rules rust-ts-mode--indent-rules)
 
+    ;; Electric
+    (setq-local electric-indent-chars
+                (append "{}():;,#" electric-indent-chars))
+
     ;; Navigation.
     (setq-local treesit-defun-type-regexp
                 (regexp-opt '("enum_item"
diff --git a/lisp/progmodes/typescript-ts-mode.el 
b/lisp/progmodes/typescript-ts-mode.el
index 7998b3740b6..7f0b7236301 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -205,7 +205,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
   (treesit-font-lock-rules
    :language language
    :feature 'comment
-   `((comment) @font-lock-comment-face)
+   `([(comment) (hash_bang_line)] @font-lock-comment-face)
 
    :language language
    :feature 'constant
diff --git a/lisp/register.el b/lisp/register.el
index 46ec38821e5..ef529cd67e5 100644
--- a/lisp/register.el
+++ b/lisp/register.el
@@ -107,8 +107,18 @@ If nil, do not show register previews, unless `help-char' 
(or a member of
   :type '(repeat string))
 
 (defcustom register-use-preview t
-  "Always show register preview when non nil."
-  :type 'boolean)
+  "Whether to show preview of registers.
+
+If the value is t, show a preview buffer with navigation and highlighting.
+If the value is nil, show a basic preview buffer and exit minibuffer
+immediately after the register name is inserted into minibuffer.
+If the value is \\='never, behave as for nil, but with no preview buffer
+at all."
+  :type '(choice
+          (const :tag "Use preview" t)
+          (const :tag "Use quick preview" nil)
+          (const :tag "Never use preview" never))
+  :version "30.1")
 
 (defun get-register (register)
   "Return contents of Emacs register named REGISTER, or nil if none."
@@ -310,11 +320,14 @@ Prompt with the string PROMPT.
 If `help-char' (or a member of `help-event-list') is pressed,
 display such a window regardless."
   (let* ((buffer "*Register Preview*")
+         (buffer1 "*Register quick preview*")
+         (buf (if register-use-preview buffer buffer1))
          (pat "")
          (map (let ((m (make-sparse-keymap)))
                 (set-keymap-parent m minibuffer-local-map)
                 m))
          (data (register-command-info this-command))
+         (enable-recursive-minibuffers t)
          types msg result timer act win strs smatch)
     (if data
         (setq types  (register-preview-info-types data)
@@ -333,15 +346,16 @@ display such a window regardless."
       (define-key map
           (vector k) (lambda ()
                        (interactive)
-                       (unless (get-buffer-window buffer)
+                       ;; Do nothing when buffer1 is in use.
+                       (unless (get-buffer-window buf)
                          (with-selected-window (minibuffer-selected-window)
                            (register-preview buffer 'show-empty types))))))
     (define-key map (kbd "<down>") 'register-preview-next)
     (define-key map (kbd "<up>")   'register-preview-previous)
     (define-key map (kbd "C-n")    'register-preview-next)
     (define-key map (kbd "C-p")    'register-preview-previous)
-    (unless (or executing-kbd-macro (null register-use-preview))
-      (register-preview buffer nil types))
+    (unless (or executing-kbd-macro (eq register-use-preview 'never))
+      (register-preview buf nil types))
     (unwind-protect
          (progn
            (minibuffer-with-setup-hook
@@ -369,7 +383,12 @@ display such a window regardless."
                                 (setq pat input))))
                           (if (setq win (get-buffer-window buffer))
                               (with-selected-window win
-                                (let ((ov (make-overlay (point-min) 
(point-min))))
+                                (let ((ov (make-overlay
+                                           (point-min) (point-min)))
+                                      ;; Allow upper-case and
+                                      ;; lower-case letters to refer
+                                      ;; to different registers.
+                                      (case-fold-search nil))
                                   (goto-char (point-min))
                                   (remove-overlays)
                                   (unless (string= pat "")
@@ -385,21 +404,25 @@ display such a window regardless."
                                         (minibuffer-message
                                          "Register `%s' is empty" pat))))))
                             (unless (string= pat "")
-                              (if (member pat strs)
-                                  (with-selected-window (minibuffer-window)
-                                    (minibuffer-message msg pat))
-                                (with-selected-window (minibuffer-window)
-                                  (minibuffer-message
-                                   "Register `%s' is empty" pat)))))))))
+                              (with-selected-window (minibuffer-window)
+                                (if (and (member pat strs) (memq act '(set 
modify)))
+                                    (with-selected-window (minibuffer-window)
+                                      (minibuffer-message msg pat))
+                                  ;; An empty register or an existing
+                                  ;; one but the action is insert or
+                                  ;; jump, don't ask for confirmation
+                                  ;; and exit immediately (bug#66394).
+                                  (setq result pat)
+                                  (exit-minibuffer)))))))))
              (setq result (read-from-minibuffer
                            prompt nil map nil nil 
(register-preview-get-defaults act))))
            (cl-assert (and result (not (string= result "")))
                       nil "No register specified")
            (string-to-char result))
       (when timer (cancel-timer timer))
-      (let ((w (get-buffer-window buffer)))
+      (let ((w (get-buffer-window buf)))
         (and (window-live-p w) (delete-window w)))
-      (and (get-buffer buffer) (kill-buffer buffer)))))
+      (and (get-buffer buf) (kill-buffer buf)))))
 
 (defun point-to-register (register &optional arg)
   "Store current location of point in REGISTER.
diff --git a/lisp/ses.el b/lisp/ses.el
index 30bf33e47bf..23018403cda 100644
--- a/lisp/ses.el
+++ b/lisp/ses.el
@@ -2245,7 +2245,7 @@ Based on the current set of columns and `window-hscroll' 
position."
 ;; Redisplay and recalculation
 ;;----------------------------------------------------------------------------
 (defun ses-jump-prefix (prefix-int)
-  "Convert an integer (unversal prefix) into a (ROW . COL).
+  "Convert an integer (universal prefix) into a (ROW . COL).
 Does it by numbering cells starting from 0 from top left to bottom right,
 going row by row."
   (and (>= prefix-int 0)
diff --git a/lisp/simple.el b/lisp/simple.el
index 9fe068cb464..d0e9ee5cc02 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -8763,7 +8763,7 @@ node `(elisp) Word Motion' for details."
 
 (defun mark-word (&optional arg allow-extend)
   "Set mark ARG words from point or move mark one word.
-When called from Lisp with ALLOW-EXTEND ommitted or nil, mark is
+When called from Lisp with ALLOW-EXTEND omitted or nil, mark is
 set ARG words from point.
 With ARG and ALLOW-EXTEND both non-nil (interactively, with prefix
 argument), the place to which mark goes is the same place \\[forward-word]
@@ -10101,6 +10101,11 @@ Also see the `completion-auto-wrap' variable."
           (if pos (goto-char pos))))
       (setq n (1+ n)))))
 
+(defvar choose-completion-deselect-if-after nil
+  "If non-nil, don't choose a completion candidate if point is right after it.
+
+This makes `completions--deselect' effective.")
+
 (defun choose-completion (&optional event no-exit no-quit)
   "Choose the completion at point.
 If EVENT, use EVENT's position to determine the starting position.
@@ -10121,6 +10126,10 @@ minibuffer, but don't quit the completions window."
           (insert-function completion-list-insert-choice-function)
           (completion-no-auto-exit (if no-exit t completion-no-auto-exit))
           (choice
+           (if choose-completion-deselect-if-after
+               (if-let ((str (get-text-property (posn-point (event-start 
event)) 'completion--string)))
+                   (substring-no-properties str)
+                 (error "No completion here"))
            (save-excursion
              (goto-char (posn-point (event-start event)))
              (let (beg)
@@ -10136,7 +10145,7 @@ minibuffer, but don't quit the completions window."
                               beg 'completion--string)
                              beg))
                (substring-no-properties
-                (get-text-property beg 'completion--string))))))
+                (get-text-property beg 'completion--string)))))))
 
       (unless (buffer-live-p buffer)
         (error "Destination buffer is dead"))
@@ -11176,10 +11185,10 @@ For each insertion:
     enabled.
 
   - Look for the deletion of a single electric pair character,
-    and delete the adjascent pair if
+    and delete the adjacent pair if
     `electric-pair-delete-adjacent-pairs'.
 
-  - Run `post-self-insert-functions' for the last character of
+  - Run `post-self-insert-hook' for the last character of
     any inserted text so that modes such as `electric-pair-mode'
     can work.
 
diff --git a/lisp/startup.el b/lisp/startup.el
index e40c316a8e8..255c31257b0 100644
--- a/lisp/startup.el
+++ b/lisp/startup.el
@@ -641,7 +641,24 @@ It is the default value of the variable `top-level'."
       (setq eol-mnemonic-dos  "(DOS)"
            eol-mnemonic-mac  "(Mac)")))
 
-    (set-locale-environment nil)
+    (if (and (featurep 'android)
+             (eq system-type 'android)
+             (fboundp 'android-locale-for-system-language)
+             initial-window-system)
+        ;; If Android windowing is enabled, derive a proper locale
+        ;; from the system's language preferences.  On Android, LANG
+        ;; and LC_* must be set to one of the two locales the C
+        ;; library supports, but, by contrast with other systems, the
+        ;; C library locale does not reflect the configured system
+        ;; language.
+        ;;
+        ;; For this reason, the locale from which Emacs derives a
+        ;; default language environment is computed from such
+        ;; preferences, rather than environment variables that the C
+        ;; library refers to.
+        (set-locale-environment
+         (funcall 'android-locale-for-system-language))
+      (set-locale-environment nil))
     ;; Decode all default-directory's (probably, only *scratch* exists
     ;; at this point).  default-directory of *scratch* is the basis
     ;; for many other file-name variables and directory lists, so it
diff --git a/lisp/subr.el b/lisp/subr.el
index 7f2dcdc4d90..93428c4a518 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -2804,7 +2804,11 @@ MODES should be a list of symbols or a single mode 
symbol instead of a list.
 We also still support the deprecated calling convention:
 \(derived-mode-p &rest MODES)."
  (declare (side-effect-free t)
-          (advertised-calling-convention (modes) "30.1"))
+          ;; FIXME: It's cumbersome for external packages to write code which
+          ;; accommodates both the old and the new calling conventions *and*
+          ;; doesn't cause spurious warnings.  So let's be more lenient
+          ;; for now and maybe remove `deprecated-args' for Emacs-31.
+          (advertised-calling-convention (modes &rest deprecated-args) "30.1"))
  (provided-mode-derived-p major-mode (if old-modes (cons modes old-modes)
                                        modes)))
 
@@ -6380,13 +6384,14 @@ If non-nil, BASE should be a function, and frames 
before its
 nearest activation frame are discarded."
   (let ((frames nil))
     (mapbacktrace (lambda (&rest frame) (push frame frames))
-                  (or base 'backtrace-frames))
+                  (or base #'backtrace-frames))
     (nreverse frames)))
 
 (defun backtrace-frame (nframes &optional base)
   "Return the function and arguments NFRAMES up from current execution point.
 If non-nil, BASE should be a function, and NFRAMES counts from its
-nearest activation frame.
+nearest activation frame.  BASE can also be of the form (OFFSET . FUNCTION)
+in which case OFFSET will be added to NFRAMES.
 If the frame has not evaluated the arguments yet (or is a special form),
 the value is (nil FUNCTION ARG-FORMS...).
 If the frame has evaluated its arguments and called its function already,
@@ -6397,7 +6402,7 @@ or a lambda expression for macro calls.
 If NFRAMES is more than the number of frames, the value is nil."
   (backtrace-frame--internal
    (lambda (evald func args _) `(,evald ,func ,@args))
-   nframes (or base 'backtrace-frame)))
+   nframes (or base #'backtrace-frame)))
 
 
 (defvar called-interactively-p-functions nil
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index e21367255a0..4fda4b027a6 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -416,6 +416,8 @@ Beep, then throw to `context-menu' and return."
   (beep)
   (throw 'context-menu 'context-menu))
 
+(defvar touch-screen-delay)
+
 (defun tab-bar-touchscreen-begin (event)
   "Handle a touchscreen begin EVENT on the tab bar.
 
diff --git a/lisp/tab-line.el b/lisp/tab-line.el
index 4637dafcd90..0c9ef72084b 100644
--- a/lisp/tab-line.el
+++ b/lisp/tab-line.el
@@ -958,6 +958,8 @@ sight of the tab line."
 
 ;;; Touch screen support.
 
+(defvar touch-screen-delay)
+
 (defun tab-line-track-tap (event &optional function)
   "Track a tap starting from EVENT.
 If EVENT is not a `touchscreen-begin' event, return t.
diff --git a/lisp/term.el b/lisp/term.el
index b2875e4a17f..d75a7d22aed 100644
--- a/lisp/term.el
+++ b/lisp/term.el
@@ -1085,6 +1085,8 @@ underlying shell."
   (setq term-ansi-current-invisible nil)
   (setq term-ansi-current-bg-color 0))
 
+(defvar touch-screen-display-keyboard)
+
 (define-derived-mode term-mode fundamental-mode "Term"
   "Major mode for interacting with an inferior interpreter.
 The interpreter name is same as buffer name, sans the asterisks.
@@ -1391,10 +1393,15 @@ Entry to this mode runs the hooks on `term-mode-hook'."
   (interactive)
    (term-send-raw-string (current-kill 0)))
 
-(defun term--xterm-paste ()
+(defun term--xterm-paste (event)
   "Insert the text pasted in an XTerm bracketed paste operation."
-  (interactive)
-  (term-send-raw-string (xterm--pasted-text)))
+  (interactive "e")
+  (unless (eq (car-safe event) 'xterm-paste)
+    (error "term--xterm-paste must be found to xterm-paste event"))
+  (let ((str (nth 1 event)))
+    (unless (stringp str)
+      (error "term--xterm-paste provided event does not contain paste text"))
+    (term-send-raw-string str)))
 
 (declare-function xterm--pasted-text "term/xterm" ())
 
diff --git a/lisp/term/android-win.el b/lisp/term/android-win.el
index 36470097b40..b2cc7b5d040 100644
--- a/lisp/term/android-win.el
+++ b/lisp/term/android-win.el
@@ -340,7 +340,7 @@ the `stop-selecting-text' editing key."
 
 
 ;; Splash screen notice.  Users are frequently left scratching their
-;; heads when they overlook the Android appendex in the Emacs manual
+;; heads when they overlook the Android appendix in the Emacs manual
 ;; and discover that external storage is not accessible; worse yet,
 ;; Android 11 and later veil the settings panel controlling such
 ;; permissions behind layer upon layer of largely immaterial settings
@@ -425,5 +425,60 @@ denied.  ")
       (newline))))
 
 
+;;; Locale preferences.
+
+(defvar android-os-language)
+
+(defun android-locale-for-system-language ()
+  "Return a locale representing the system language.
+This locale reflects the system's language preferences in its
+language name and country variant fields, and always specifies
+the UTF-8 coding system."
+  ;; android-os-language is a list comprising four elements LANGUAGE,
+  ;; COUNTRY, SCRIPT, and VARIANT.
+  ;;
+  ;; LANGUAGE and COUNTRY are ISO language and country codes identical
+  ;; to those stored within POSIX locales.
+  ;;
+  ;; SCRIPT is an ISO 15924 script tag, representing the script used
+  ;; if available, or if required to disambiguate between distinct
+  ;; writing systems for the same combination of language and country.
+  ;;
+  ;; VARIANT is an arbitrary string representing the variant of the
+  ;; LANGUAGE or SCRIPT represented.
+  ;;
+  ;; Each of these fields might be empty, but the locale is invalid if
+  ;; LANGUAGE is empty, which if true "en_US.UTF-8" is returned as a
+  ;; placeholder.
+  (let ((language (or (nth 0 android-os-language) ""))
+        (country (or (nth 1 android-os-language) ""))
+        (script (or (nth 2 android-os-language) ""))
+        (variant (or (nth 3 android-os-language) ""))
+        locale-base locale-modifier)
+    (if (string-empty-p language)
+        (setq locale-base "en_US.UTF-8")
+      (if (string-empty-p country)
+          (setq locale-base (concat language ".UTF-8"))
+        (setq locale-base (concat language "_" country
+                                  ".UTF-8"))))
+    ;; No straightforward relation between Java script and variant
+    ;; combinations exist: Java permits both a script and a variant to
+    ;; be supplied at once, whereas POSIX's closest analog "modifiers"
+    ;; permit only either an alternative script or a variant to be
+    ;; supplied.
+    ;;
+    ;; Emacs disregards variants besides "EURO" and scripts besides
+    ;; "Cyrl", for these two never coexist in existing locales, and
+    ;; their POSIX equivalents are the sole modifiers recognized by
+    ;; Emacs.
+    (if (string-equal script "Cyrl")
+        (setq locale-modifier "@cyrillic")
+      (if (string-equal variant "EURO")
+          (setq locale-modifier "@euro")
+        (setq locale-modifier "")))
+    ;; Return the concatenation of both these values.
+    (concat locale-base locale-modifier)))
+
+
 (provide 'android-win)
 ;; android-win.el ends here.
diff --git a/lisp/term/linux.el b/lisp/term/linux.el
index f24af3f1344..491649a053d 100644
--- a/lisp/term/linux.el
+++ b/lisp/term/linux.el
@@ -13,9 +13,13 @@
   ;; Compositions confuse cursor movement.
   (setq-default auto-composition-mode "linux")
 
+  ;; Ensure additional terminal setup is done when `gpm-mouse-mode' is
+  ;; enabled.
+  (ignore-errors (when gpm-mouse-mode (gpm-mouse-mode 1)))
+
   ;; Don't translate ESC TAB to backtab as directed by ncurses-6.3.
   (define-key input-decode-map "\e\t" nil)
-  
+
   ;; Make Latin-1 input characters work, too.
   ;; Meta will continue to work, because the kernel turns that into Escape.
 
diff --git a/lisp/textmodes/ispell.el b/lisp/textmodes/ispell.el
index 4c3b22281bd..2c387342026 100644
--- a/lisp/textmodes/ispell.el
+++ b/lisp/textmodes/ispell.el
@@ -3699,7 +3699,6 @@ If APPEND is non-nil, don't erase previous debugging 
output."
              (setcdr cur (cddr cur)))
            (setq cur (cdr cur)))
          (list beg end (cdr all)
-               :annotation-function (lambda (_) " Dictionary word")
                :exclusive 'no))))))
 
 
diff --git a/lisp/thingatpt.el b/lisp/thingatpt.el
index 88efbf73beb..80dc5ee60b7 100644
--- a/lisp/thingatpt.el
+++ b/lisp/thingatpt.el
@@ -652,7 +652,7 @@ back from point."
 
 ;;   Email addresses
 (defvar thing-at-point-email-regexp
-  "<?[-+_~a-zA-Z0-9][-+_.~:a-zA-Z0-9]*@[-a-zA-Z0-9]+[-.a-zA-Z0-9]*>?"
+  "<?[-+_~a-zA-Z0-9/][-+_.~:a-zA-Z0-9/]*@[-a-zA-Z0-9]+[-.a-zA-Z0-9]*>?"
   "A regular expression probably matching an email address.
 This does not match the real name portion, only the address, optionally
 with angle brackets.")
diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el
index 56adb75cefc..a10bdea8994 100644
--- a/lisp/touch-screen.el
+++ b/lisp/touch-screen.el
@@ -57,7 +57,7 @@ touch point being tracked, the window where the touch began, a
 cons holding the initial position of the touch point, and the
 last known position of the touch point, all in the same format as
 in `touch-screen-current-tool', the distance in pixels between
-the current tool and the aformentioned initial position, the
+the current tool and the aforementioned initial position, the
 center of the line formed between those two points, the ratio
 between the present distance between both tools and the aforesaid
 initial distance when a pinch gesture was last sent, and three
@@ -320,6 +320,7 @@ the event."
 
 ;;; Drag-to-select gesture.
 
+;;;###autoload
 (defun touch-screen-hold (event)
   "Handle a long press EVENT.
 Ding and select the window at EVENT, then activate the mark.  If
@@ -1913,6 +1914,7 @@ if POSN is on a link or a button, or `mouse-1' otherwise."
 
 ;; Exports.  These functions are intended for use externally.
 
+;;;###autoload
 (defun touch-screen-track-tap (event &optional update data threshold)
   "Track a single tap starting from EVENT.
 EVENT should be a `touchscreen-begin' event.
@@ -1925,7 +1927,7 @@ with that event and DATA.
 
 If THRESHOLD is non-nil, enforce a threshold of movement that is
 either itself or 10 pixels when it is not a number.  If the
-aformentioned touch point moves beyond that threshold on any
+aforementioned touch point moves beyond that threshold on any
 axis, return nil immediately, and further resume mouse event
 translation for the touch point at hand.
 
@@ -1970,6 +1972,7 @@ otherwise, return t once the `touchscreen-end' event 
arrives."
                    (eq (caadr event) (caadr new-event))))
            (t (throw 'finish nil))))))))
 
+;;;###autoload
 (defun touch-screen-track-drag (event update &optional data)
   "Track a single drag starting from EVENT.
 EVENT should be a `touchscreen-begin' event.
@@ -2017,6 +2020,7 @@ touch point in EVENT did not move significantly, and t 
otherwise."
 ;;; Event handling exports.  These functions are intended for use by
 ;;; Lisp commands bound to touch screen gesture events.
 
+;;;###autoload
 (defun touch-screen-inhibit-drag ()
   "Inhibit subsequent `touchscreen-drag' events from being sent.
 Prevent `touchscreen-drag' and translated mouse events from being
diff --git a/lisp/transient.el b/lisp/transient.el
index dd2b4e0db0b..93c68f8162b 100644
--- a/lisp/transient.el
+++ b/lisp/transient.el
@@ -5,9 +5,7 @@
 ;; Author: Jonas Bernoulli <jonas@bernoul.li>
 ;; URL: https://github.com/magit/transient
 ;; Keywords: extensions
-
-;; Package-Version: 0.4.3
-;; Package-Requires: ((emacs "26.1"))
+;; Version: 0.5.2
 
 ;; SPDX-License-Identifier: GPL-3.0-or-later
 
@@ -28,27 +26,9 @@
 
 ;;; Commentary:
 
-;; 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
-;; commands (a prefix and a suffix) we prefer to call it just a
-;; "transient".
-
-;; When the user calls a transient prefix command, then a transient
-;; (temporary) keymap is activated, which binds the transient's infix
-;; and suffix commands, and functions that control the transient state
-;; are added to `pre-command-hook' and `post-command-hook'.  The
-;; available suffix and infix commands and their state are shown in
-;; the echo area until the transient is exited by invoking a suffix
-;; command.
-
-;; Calling an infix command causes its value to be changed, possibly
-;; by reading a new value in the minibuffer.
-
-;; Calling a suffix command usually causes the transient to be exited
-;; but suffix commands can also be configured to not exit the
-;; transient state.
+;; Transient is the library used to implement the keyboard-driven menus
+;; in Magit.  It is distributed as a separate package, so that it can be
+;; used to implement similar menus in other packages.
 
 ;;; Code:
 
@@ -56,7 +36,41 @@
 (require 'eieio)
 (require 'edmacro)
 (require 'format-spec)
+
+(eval-and-compile
+  (when (and (featurep' seq)
+             (not (fboundp 'seq-keep)))
+    (unload-feature 'seq 'force)))
 (require 'seq)
+(unless (fboundp 'seq-keep)
+  (display-warning 'transient (substitute-command-keys "\
+Transient requires `seq' >= 2.24,
+but due to bad defaults, Emacs' package manager, refuses to
+upgrade this and other built-in packages to higher releases
+from GNU Elpa, when a package specifies that this is needed.
+
+To fix this, you have to add this to your init file:
+
+  (setq package-install-upgrade-built-in t)
+
+Then evaluate that expression by placing the cursor after it
+and typing \\[eval-last-sexp].
+
+Once you have done that, you have to explicitly upgrade `seq':
+
+  \\[package-upgrade] seq \\`RET'
+
+Then you also must make sure the updated version is loaded,
+by evaluating this form:
+
+  (progn (unload-feature 'seq t) (require 'seq))
+
+Until you do this, you will get random errors about `seq-keep'
+being undefined while using Transient.
+
+If you don't use the `package' package manager but still get
+this warning, then your chosen package manager likely has a
+similar defect.") :emergency))
 
 (eval-when-compile (require 'subr-x))
 
@@ -65,10 +79,20 @@
 (declare-function Man-next-section "man" (n))
 (declare-function Man-getpage-in-background "man" (topic))
 
-(defvar display-line-numbers) ; since Emacs 26.1
 (defvar Man-notify-method)
 (defvar pp-default-function) ; since Emacs 29.1
 
+(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 transient--with-emergency-exit (&rest body)
   (declare (indent defun))
   `(condition-case err
@@ -198,21 +222,30 @@ If nil, then the buffer has no mode-line.  If the buffer 
is not
 displayed right above the echo area, then this probably is not
 a good value.
 
-If `line' (the default), then the buffer also has no mode-line,
-but a thin line is drawn instead, using the background color of
-the face `transient-separator'.  Termcap frames cannot display
-thin lines and therefore fallback to treating `line' like nil.
+If `line' (the default) or a natural number, then the buffer
+has no mode-line, but a line is drawn is drawn in its place.
+If a number is used, that specifies the thickness of the line.
+On termcap frames we cannot draw lines, so there `line' and
+numbers are synonyms for nil.
+
+The color of the line is used to indicate if non-suffixes are
+allowed and whether they exit the transient.  The foreground
+color of `transient-key-noop' (if non-suffix are disallowed),
+`transient-key-stay' (if allowed and transient stays active), or
+`transient-key-exit' (if allowed and they exit the transient) is
+used to draw the line.
 
 Otherwise this can be any mode-line format.
 See `mode-line-format' for details."
   :package-version '(transient . "0.2.0")
   :group 'transient
-  :type '(choice (const :tag "hide mode-line" nil)
-                 (const :tag "substitute thin line" line)
-                 (const :tag "name of prefix command"
-                        ("%e" mode-line-front-space
-                         mode-line-buffer-identification))
-                 (sexp  :tag "custom mode-line format")))
+  :type '(choice (const  :tag "hide mode-line" nil)
+                 (const  :tag "substitute thin line" line)
+                 (number :tag "substitute line with thickness")
+                 (const  :tag "name of prefix command"
+                         ("%e" mode-line-front-space
+                          mode-line-buffer-identification))
+                 (sexp   :tag "custom mode-line format")))
 
 (defcustom transient-show-common-commands nil
   "Whether to show common transient suffixes in the popup buffer.
@@ -236,7 +269,7 @@ of this variable use \"C-x t\" when a transient is active."
 This only affects infix arguments that represent command-line
 arguments.  When this option is non-nil, then the key binding
 for infix argument are highlighted when only a long argument
-\(e.g. \"--verbose\") is specified but no shor-thand (e.g \"-v\").
+\(e.g., \"--verbose\") is specified but no shorthand (e.g., \"-v\").
 In the rare case that a short-hand is specified but does not
 match the key binding, then it is highlighted differently.
 
@@ -285,19 +318,14 @@ using a layout optimized for Lisp.
   :group 'transient
   :type '(choice (const :tag "Transform no keys (nil)" nil) function))
 
-(defcustom transient-semantic-coloring nil
-  "Whether to color prefixes and suffixes in Hydra-like fashion.
-This feature is experimental.
+(defcustom transient-semantic-coloring t
+  "Whether to use colors to indicate transient behavior.
 
 If non-nil, then the key binding of each suffix is colorized to
-indicate whether it exits the transient state or not.  The color
-of the prefix is indicated using the line that is drawn when the
-value of `transient-mode-line-format' is `line'.
-
-For more information about how Hydra uses colors see
-https://github.com/abo-abo/hydra#color and
-https://oremacs.com/2015/02/19/hydra-colors-reloaded.";
-  :package-version '(transient . "0.3.0")
+indicate whether it exits the transient state or not, and the
+line that is drawn below the transient popup buffer is used to
+indicate the behavior of non-suffix commands."
+  :package-version '(transient . "0.5.0")
   :group 'transient
   :type 'boolean)
 
@@ -356,8 +384,8 @@ text and might otherwise have to scroll in two dimensions."
   :group 'transient
   :type 'boolean)
 
+(defconst transient--max-level 7)
 (defconst transient--default-child-level 1)
-
 (defconst transient--default-prefix-level 4)
 
 (defcustom transient-default-level transient--default-prefix-level
@@ -436,22 +464,18 @@ give you as many additional suffixes as you hoped.)"
   "Face used for headings."
   :group 'transient-faces)
 
-(defface transient-key '((t :inherit font-lock-builtin-face))
-  "Face used for keys."
-  :group 'transient-faces)
-
-(defface transient-argument '((t :inherit font-lock-warning-face))
+(defface transient-argument '((t :inherit font-lock-string-face :weight bold))
   "Face used for enabled arguments."
   :group 'transient-faces)
 
-(defface transient-value '((t :inherit font-lock-string-face))
-  "Face used for values."
-  :group 'transient-faces)
-
 (defface transient-inactive-argument '((t :inherit shadow))
   "Face used for inactive arguments."
   :group 'transient-faces)
 
+(defface transient-value '((t :inherit font-lock-string-face :weight bold))
+  "Face used for values."
+  :group 'transient-faces)
+
 (defface transient-inactive-value '((t :inherit shadow))
   "Face used for inactive values."
   :group 'transient-faces)
@@ -460,28 +484,14 @@ give you as many additional suffixes as you hoped.)"
   "Face used for suffixes unreachable from the current prefix sequence."
   :group 'transient-faces)
 
-(defface transient-active-infix '((t :inherit secondary-selection))
-  "Face used for the infix for which the value is being read."
-  :group 'transient-faces)
-
-(defface transient-unreachable-key '((t :inherit (transient-key shadow)))
-  "Face used for keys unreachable from the current prefix sequence."
-  :group 'transient-faces)
-
-(defface transient-nonstandard-key '((t :underline t))
-  "Face optionally used to highlight keys conflicting with short-argument.
-Also see option `transient-highlight-mismatched-keys'."
-  :group 'transient-faces)
-
-(defface transient-mismatched-key '((t :underline t))
-  "Face optionally used to highlight keys without a short-argument.
-Also see option `transient-highlight-mismatched-keys'."
-  :group 'transient-faces)
-
 (defface transient-inapt-suffix '((t :inherit shadow :italic t))
   "Face used for suffixes that are inapt at this time."
   :group 'transient-faces)
 
+(defface transient-active-infix '((t :inherit highlight))
+  "Face used for the infix for which the value is being read."
+  :group 'transient-faces)
+
 (defface transient-enabled-suffix
   '((t :background "green" :foreground "black" :weight bold))
   "Face used for enabled levels while editing suffix levels.
@@ -494,63 +504,83 @@ See info node `(transient)Enabling and Disabling 
Suffixes'."
 See info node `(transient)Enabling and Disabling Suffixes'."
   :group 'transient-faces)
 
-(defface transient-higher-level '((t :underline t))
+(defface transient-higher-level
+  `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1)
+              :color ,(let ((color (face-attribute 'shadow :foreground nil t)))
+                        (or (and (not (eq color 'unspecified)) color)
+                            "grey60")))))
   "Face optionally used to highlight suffixes on higher levels.
 Also see option `transient-highlight-higher-levels'."
   :group 'transient-faces)
 
-(defface transient-separator
-  `((((class color) (background light))
-     ,@(and (>= emacs-major-version 27) '(:extend t))
-     :background "grey80")
-    (((class color) (background  dark))
-     ,@(and (>= emacs-major-version 27) '(:extend t))
-     :background "grey30"))
-  "Face used to draw line below transient popup window.
-This is only used if `transient-mode-line-format' is `line'.
-Only the background color is significant."
+(defface transient-delimiter '((t :inherit shadow))
+  "Face used for delimiters and separators.
+This includes the parentheses around values and the pipe
+character used to separate possible values from each other."
   :group 'transient-faces)
 
-(defgroup transient-color-faces
-  '((transient-semantic-coloring custom-variable))
-  "Faces used by Transient for Hydra-like command coloring.
-These faces are only used if `transient-semantic-coloring'
-\(which see) is non-nil."
+(defface transient-key '((t :inherit font-lock-builtin-face))
+  "Face used for keys."
   :group 'transient-faces)
 
-(defface transient-red
-  '((t :inherit transient-key :foreground "red"))
-  "Face used for red prefixes and suffixes."
-  :group 'transient-color-faces)
+(defface transient-key-stay
+  `((((class color) (background light))
+     :inherit transient-key
+     :foreground "#22aa22")
+    (((class color) (background dark))
+     :inherit transient-key
+     :foreground "#ddffdd"))
+  "Face used for keys of suffixes that don't exit transient state."
+  :group 'transient-faces)
 
-(defface transient-blue
-  '((t :inherit transient-key :foreground "blue"))
-  "Face used for blue prefixes and suffixes."
-  :group 'transient-color-faces)
+(defface transient-key-noop
+  `((((class color) (background light))
+     :inherit transient-key
+     :foreground "grey80")
+    (((class color) (background dark))
+     :inherit transient-key
+     :foreground "grey30"))
+  "Face used for keys of suffixes that currently cannot be invoked."
+  :group 'transient-faces)
 
-(defface transient-amaranth
-  '((t :inherit transient-key :foreground "#E52B50"))
-  "Face used for amaranth prefixes."
-  :group 'transient-color-faces)
+(defface transient-key-return
+  `((((class color) (background light))
+     :inherit transient-key
+     :foreground "#aaaa11")
+    (((class color) (background dark))
+     :inherit transient-key
+     :foreground "#ffffcc"))
+  "Face used for keys of suffixes that return to the parent transient."
+  :group 'transient-faces)
 
-(defface transient-pink
-  '((t :inherit transient-key :foreground "#FF6EB4"))
-  "Face used for pink prefixes."
-  :group 'transient-color-faces)
+(defface transient-key-exit
+  `((((class color) (background light))
+     :inherit transient-key
+     :foreground "#aa2222")
+    (((class color) (background dark))
+     :inherit transient-key
+     :foreground "#ffdddd"))
+  "Face used for keys of suffixes that exit transient state."
+  :group 'transient-faces)
 
-(defface transient-teal
-  '((t :inherit transient-key :foreground "#367588"))
-  "Face used for teal prefixes."
-  :group 'transient-color-faces)
+(defface transient-unreachable-key
+  '((t :inherit (shadow transient-key) :weight normal))
+  "Face used for keys unreachable from the current prefix sequence."
+  :group 'transient-faces)
 
-(defface transient-purple
-  '((t :inherit transient-key :foreground "#a020f0"))
-  "Face used for purple prefixes.
+(defface transient-nonstandard-key
+  `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1)
+              :color "cyan")))
+  "Face optionally used to highlight keys conflicting with short-argument.
+Also see option `transient-highlight-mismatched-keys'."
+  :group 'transient-faces)
 
-This is an addition to the colors supported by Hydra.  It is
-used by suffixes that quit the current prefix but return to
-the previous prefix."
-  :group 'transient-color-faces)
+(defface transient-mismatched-key
+  `((t :box ( :line-width ,(if (>= emacs-major-version 28) (cons -1 -1) -1)
+              :color "magenta")))
+  "Face optionally used to highlight keys without a short-argument.
+Also see option `transient-highlight-mismatched-keys'."
+  :group 'transient-faces)
 
 ;;; Persistence
 
@@ -633,6 +663,8 @@ If `transient-save-history' is nil, then do nothing."
    (man-page    :initarg :man-page    :initform nil)
    (transient-suffix     :initarg :transient-suffix     :initform nil)
    (transient-non-suffix :initarg :transient-non-suffix :initform nil)
+   (transient-switch-frame :initarg :transient-switch-frame)
+   (refresh-suffixes     :initarg :refresh-suffixes     :initform nil)
    (incompatible         :initarg :incompatible         :initform nil)
    (suffix-description   :initarg :suffix-description)
    (variable-pitch       :initarg :variable-pitch       :initform nil)
@@ -698,7 +730,9 @@ slot is non-nil."
    (transient   :initarg :transient)
    (format      :initarg :format      :initform " %k %d")
    (description :initarg :description :initform nil)
+   (face        :initarg :face        :initform nil)
    (show-help   :initarg :show-help   :initform nil)
+   (inapt-face  :initarg :inapt-face  :initform 'transient-inapt-suffix)
    (inapt                             :initform nil)
    (inapt-if
     :initarg :inapt-if
@@ -734,6 +768,12 @@ slot is non-nil."
     :documentation "Inapt if major-mode does not derive from value."))
   "Superclass for suffix command.")
 
+(defclass transient-information (transient-suffix)
+  ((format :initform " %k %d")
+   (key    :initform " "))
+  "Display-only information.
+A suffix object with no associated command.")
+
 (defclass transient-infix (transient-suffix)
   ((transient                         :initform t)
    (argument    :initarg :argument)
@@ -788,8 +828,8 @@ They become the value of this argument.")
   ((suffixes       :initarg :suffixes       :initform nil)
    (hide           :initarg :hide           :initform nil)
    (description    :initarg :description    :initform nil)
-   (setup-children :initarg :setup-children)
-   (pad-keys       :initarg :pad-keys))
+   (pad-keys       :initarg :pad-keys       :initform nil)
+   (setup-children :initarg :setup-children))
   "Abstract superclass of all group classes."
   :abstract t)
 
@@ -932,11 +972,11 @@ explicitly.
 
 The function definitions is always:
 
-   (lambda ()
-     (interactive)
-     (let ((obj (transient-suffix-object)))
-       (transient-infix-set obj (transient-infix-read obj)))
-     (transient--show))
+  (lambda ()
+    (interactive)
+    (let ((obj (transient-suffix-object)))
+      (transient-infix-set obj (transient-infix-read obj)))
+    (transient--show))
 
 `transient-infix-read' and `transient-infix-set' are generic
 functions.  Different infix commands behave differently because
@@ -973,7 +1013,16 @@ example, sets a variable, use `transient-define-infix' 
instead.
 \(fn NAME ARGLIST [DOCSTRING] [KEYWORD VALUE]...)")
 
 (defun transient--default-infix-command ()
-  "Most transient infix commands are but an alias for this command."
+  ;; Most infix commands are but an alias for this command.
+  "Cannot show any documentation for this anonymous infix command.
+
+This infix command was defined anonymously, i.e., it was define
+inside a call to `transient-define-prefix'.
+
+When you request help for such an infix command, then we usually
+show the respective man-page and jump to the location where the
+respective argument is being described.  This isn't possible in
+this case, because the `man-page' slot was not set in this case."
   (interactive)
   (let ((obj (transient-suffix-object)))
     (transient-infix-set obj (transient-infix-read obj)))
@@ -981,30 +1030,31 @@ example, sets a variable, use `transient-define-infix' 
instead.
 (put 'transient--default-infix-command 'interactive-only t)
 (put 'transient--default-infix-command 'command-modes (list 'not-a-mode))
 
-(defun transient--expand-define-args (args &optional arglist)
-  (unless (listp arglist)
-    (error "Mandatory ARGLIST is missing"))
-  (let (class keys suffixes docstr)
-    (when (stringp (car args))
-      (setq docstr (pop args)))
-    (while (keywordp (car args))
-      (let ((k (pop args))
-            (v (pop args)))
-        (if (eq k :class)
-            (setq class v)
-          (push k keys)
-          (push v keys))))
-    (while (let ((arg (car args)))
-             (or (vectorp arg)
-                 (and arg (symbolp arg))))
-      (push (pop args) suffixes))
-    (list (if (eq (car-safe class) 'quote)
-              (cadr class)
-            class)
-          (nreverse keys)
-          (nreverse suffixes)
-          docstr
-          args)))
+(eval-and-compile
+  (defun transient--expand-define-args (args &optional arglist)
+    (unless (listp arglist)
+      (error "Mandatory ARGLIST is missing"))
+    (let (class keys suffixes docstr)
+      (when (stringp (car args))
+        (setq docstr (pop args)))
+      (while (keywordp (car args))
+        (let ((k (pop args))
+              (v (pop args)))
+          (if (eq k :class)
+              (setq class v)
+            (push k keys)
+            (push v keys))))
+      (while (let ((arg (car args)))
+               (or (vectorp arg)
+                   (and arg (symbolp arg))))
+        (push (pop args) suffixes))
+      (list (if (eq (car-safe class) 'quote)
+                (cadr class)
+              class)
+            (nreverse keys)
+            (nreverse suffixes)
+            docstr
+            args))))
 
 (defun transient--parse-child (prefix spec)
   (cl-etypecase spec
@@ -1069,8 +1119,9 @@ example, sets a variable, use `transient-define-infix' 
instead.
              (commandp (cadr spec)))
         (setq args (plist-put args :description (macroexp-quote pop)))))
       (cond
+       ((eq car :info))
        ((keywordp car)
-        (error "Need command, got `%s'" car))
+        (error "Need command or `:info', got `%s'" car))
        ((symbolp car)
         (setq args (plist-put args :command (macroexp-quote pop))))
        ((and (commandp car)
@@ -1088,7 +1139,10 @@ example, sets a variable, use `transient-define-infix' 
instead.
                       `(prog1 ',sym
                          (put ',sym 'interactive-only t)
                          (put ',sym 'command-modes (list 'not-a-mode))
-                         (defalias ',sym ,(macroexp-quote cmd)))))))
+                         (defalias ',sym
+                           ,(if (eq (car-safe cmd) 'lambda)
+                                cmd
+                              (macroexp-quote cmd))))))))
        ((or (stringp car)
             (and car (listp car)))
         (let ((arg pop)
@@ -1123,6 +1177,9 @@ example, sets a variable, use `transient-define-infix' 
instead.
               (val pop))
           (cond ((eq key :class) (setq class val))
                 ((eq key :level) (setq level val))
+                ((eq key :info)
+                 (setq class 'transient-information)
+                 (setq args (plist-put args :description val)))
                 ((eq (car-safe val) '\,)
                  (setq args (plist-put args key (cadr val))))
                 ((or (symbolp val)
@@ -1191,11 +1248,11 @@ Intended for use in a group's `:setup-children' 
function."
                         (equal (transient--suffix-predicate suf)
                                (transient--suffix-predicate conflict)))))
         (transient-remove-suffix prefix key))
-      (cl-ecase action
-        (insert  (setcdr mem (cons elt (cdr mem)))
-                 (setcar mem suf))
-        (append  (setcdr mem (cons suf (cdr mem))))
-        (replace (setcar mem suf)))))))
+      (pcase-exhaustive action
+        ('insert  (setcdr mem (cons elt (cdr mem)))
+                  (setcar mem suf))
+        ('append  (setcdr mem (cons suf (cdr mem))))
+        ('replace (setcar mem suf)))))))
 
 ;;;###autoload
 (defun transient-insert-suffix (prefix loc suffix &optional keep-other)
@@ -1306,7 +1363,7 @@ See info node `(transient)Modifying Existing Transients'."
                (delq (car (transient--group-member loc layout))
                      (aref layout 3)))
          nil)
-        (t (transient--group-member loc layout))))
+        ((transient--group-member loc layout))))
 
 (defun transient--group-member (loc group)
   (cl-member-if (lambda (suffix)
@@ -1335,7 +1392,7 @@ See info node `(transient)Modifying Existing Transients'."
          (plist-get plist :command)))))
 
 (defun transient--command-key (cmd)
-  (and-let* ((obj (get cmd 'transient--suffix)))
+  (and-let* ((obj (transient--suffix-prototype cmd)))
     (cond ((slot-boundp obj 'key)
            (oref obj key))
           ((slot-exists-p obj 'shortarg)
@@ -1376,11 +1433,15 @@ variable instead.")
 (defconst transient--exit nil "Do exit the transient.")
 
 (defvar transient--exitp nil "Whether to exit the transient.")
-(defvar transient--showp nil "Whether the transient is show in a popup 
buffer.")
+(defvar transient--showp nil "Whether to show the transient popup buffer.")
 (defvar transient--helpp nil "Whether help-mode is active.")
 (defvar transient--editp nil "Whether edit-mode is active.")
 
-(defvar transient--active-infix nil "The active infix awaiting user input.")
+(defvar transient--refreshp nil
+  "Whether to refresh the transient completely.")
+
+(defvar transient--all-levels-p nil
+  "Whether temporary display of suffixes on all levels is active.")
 
 (defvar transient--timer nil)
 
@@ -1392,7 +1453,7 @@ variable instead.")
   "Name of the transient buffer.")
 
 (defvar transient--window nil
-  "The window used to display the transient popup.")
+  "The window used to display the transient popup buffer.")
 
 (defvar transient--original-window nil
   "The window that was selected before the transient was invoked.
@@ -1402,7 +1463,24 @@ Usually it remains selected while the transient is 
active.")
   "The buffer that was current before the transient was invoked.
 Usually it remains current while the transient is active.")
 
-(defvar transient--debug nil "Whether put debug information into *Messages*.")
+(defvar transient--restore-winconf nil
+  "Window configuration to restore after exiting help.")
+
+(defvar transient--shadowed-buffer nil
+  "The buffer that is temporarily shadowed by the transient buffer.
+This is bound while the suffix predicate is being evaluated and while
+drawing in the transient buffer.")
+
+(defvar transient--pending-suffix nil
+  "The suffix that is currently being processed.
+This is bound while the suffix predicate is being evaluated.")
+
+(defvar transient--pending-group nil
+  "The group that is currently being processed.
+This is bound while the suffixes are drawn in the transient buffer.")
+
+(defvar transient--debug nil
+  "Whether to put debug information into *Messages*.")
 
 (defvar transient--history nil)
 
@@ -1414,6 +1492,31 @@ Usually it remains current while the transient is 
active.")
 
 ;;; Identities
 
+(defun transient-prefix-object ()
+  "Return the current prefix as an object.
+
+While a transient is being setup or refreshed (which involves
+preparing its suffixes) the variable `transient--prefix' can be
+used to access the prefix object.  Thus this is what has to be
+used in suffix methods such as `transient-format-description',
+and in object-specific functions that are stored in suffix slots
+such as `description'.
+
+When a suffix command is invoked (i.e., in its `interactive' form
+and function body) then the variable `transient-current-prefix'
+has to be used instead.
+
+Two distinct variables are needed, because any prefix may itself
+be used as a suffix of another prefix, and such sub-prefixes have
+to be able to tell themselves apart from the prefix they were
+invoked from.
+
+Regular suffix commands, which are not prefixes, do not have to
+concern themselves with this distinction, so they can use this
+function instead.  In the context of a plain suffix, it always
+returns the value of the appropriate variable."
+  (or transient--prefix transient-current-prefix))
+
 (defun transient-suffix-object (&optional command)
   "Return the object associated with the current suffix command.
 
@@ -1425,11 +1528,11 @@ This function is intended to be called by infix 
commands, which
 are usually aliases of `transient--default-infix-command', which
 is defined like this:
 
-   (defun transient--default-infix-command ()
-     (interactive)
-     (let ((obj (transient-suffix-object)))
-       (transient-infix-set obj (transient-infix-read obj)))
-     (transient--show))
+  (defun transient--default-infix-command ()
+    (interactive)
+    (let ((obj (transient-suffix-object)))
+      (transient-infix-set obj (transient-infix-read obj)))
+    (transient--show))
 
 \(User input is read outside of `interactive' to prevent the
 command from being added to `command-history'.  See #23.)
@@ -1474,12 +1577,17 @@ probably use this instead:
                            (listify-key-sequence (this-command-keys))))
                   suffixes))
             (car suffixes)))
-    (when-let* ((obj (get (or command this-command) 'transient--suffix))
-                (obj (clone obj)))
-      ;; Cannot use and-let* because of debbugs#31840.
-      (transient-init-scope obj)
-      (transient-init-value obj)
-      obj)))
+    (and-let* ((obj (transient--suffix-prototype (or command this-command)))
+               (obj (clone obj)))
+      (progn ; work around debbugs#31840
+        (transient-init-scope obj)
+        (transient-init-value obj)
+        obj))))
+
+(defun transient--suffix-prototype (command)
+  (or (get command 'transient--suffix)
+      (seq-some (lambda (cmd) (get cmd 'transient--suffix))
+                (function-alias-p command))))
 
 ;;; Keymaps
 
@@ -1570,7 +1678,8 @@ to `transient-predicate-map'.  Also see 
`transient-base-map'."
                        (if transient-show-common-commands
                            "Hide common commands"
                          "Show common permanently")))
-               (list "C-x l" "Show/hide suffixes" #'transient-set-level))))))))
+               (list "C-x l" "Show/hide suffixes" #'transient-set-level)
+               (list "C-x a" #'transient-toggle-level-limit))))))))
 
 (defvar-keymap transient-popup-navigation-map
   :doc "One of the keymaps used when popup navigation is enabled.
@@ -1588,6 +1697,16 @@ See `transient-enable-popup-navigation'."
   "<mouse-1>" #'transient-push-button
   "<mouse-2>" #'transient-push-button)
 
+(defvar-keymap transient-resume-mode-map
+  :doc "Keymap for `transient-resume-mode'.
+
+This keymap remaps every command that would usually just quit the
+documentation buffer to `transient-resume', which additionally
+resumes the suspended transient."
+  "<remap> <Man-quit>"    #'transient-resume
+  "<remap> <Info-exit>"   #'transient-resume
+  "<remap> <quit-window>" #'transient-resume)
+
 (defvar-keymap transient-predicate-map
   :doc "Base keymap used to map common commands to their transient behavior.
 
@@ -1623,7 +1742,9 @@ of the corresponding object."
   "<transient-update>"            #'transient--do-stay
   "<transient-toggle-common>"     #'transient--do-stay
   "<transient-set>"               #'transient--do-call
+  "<transient-set-and-exit>"      #'transient--do-exit
   "<transient-save>"              #'transient--do-call
+  "<transient-save-and-exit>"     #'transient--do-exit
   "<transient-reset>"             #'transient--do-call
   "<describe-key-briefly>"        #'transient--do-stay
   "<describe-key>"                #'transient--do-stay
@@ -1699,50 +1820,66 @@ of the corresponding object."
     map))
 
 (defun transient--make-predicate-map ()
-  (let ((map (make-sparse-keymap)))
+  (let* ((default (transient--resolve-pre-command
+                   (oref transient--prefix transient-suffix)))
+         (return (and transient-current-prefix (eq default t)))
+         (map (make-sparse-keymap)))
     (set-keymap-parent map transient-predicate-map)
-    (when (memq (oref transient--prefix transient-non-suffix)
-                '(nil transient--do-warn transient--do-noop))
-      (keymap-set map "<handle-switch-frame>" #'transient--do-suspend))
+    (when (or (and (slot-boundp transient--prefix 'transient-switch-frame)
+                   (transient--resolve-pre-command
+                    (not (oref transient--prefix transient-switch-frame))))
+              (memq (transient--resolve-pre-command
+                     (oref transient--prefix transient-non-suffix))
+                    '(nil transient--do-warn transient--do-noop)))
+      (define-key map [handle-switch-frame] #'transient--do-suspend))
     (dolist (obj transient--suffixes)
       (let* ((cmd (oref obj command))
-             (sub-prefix (and (symbolp cmd) (get cmd 'transient--prefix) t)))
+             (kind (cond ((get cmd 'transient--prefix)    'prefix)
+                         ((cl-typep obj 'transient-infix) 'infix)
+                         (t                               'suffix))))
         (cond
          ((oref obj inapt)
           (define-key map (vector cmd) #'transient--do-warn-inapt))
          ((slot-boundp obj 'transient)
           (define-key map (vector cmd)
-            (let ((do (oref obj transient)))
-              (pcase (list do sub-prefix)
-                ('(t     t) #'transient--do-recurse)
-                ('(t   nil) (if (cl-typep obj 'transient-infix)
-                                #'transient--do-stay
-                              #'transient--do-call))
-                ('(nil   t) #'transient--do-replace)
-                ('(nil nil) #'transient--do-exit)
-                (_          do)))))
+            (pcase (list kind
+                         (transient--resolve-pre-command (oref obj transient))
+                         return)
+              (`(prefix   t ,_) #'transient--do-recurse)
+              (`(prefix nil ,_) #'transient--do-stack)
+              (`(infix    t ,_) #'transient--do-stay)
+              (`(suffix   t ,_) #'transient--do-call)
+              ('(suffix nil  t) #'transient--do-return)
+              (`(,_     nil ,_) #'transient--do-exit)
+              (`(,_     ,do ,_) do))))
          ((not (lookup-key transient-predicate-map (vector cmd)))
           (define-key map (vector cmd)
-            (if sub-prefix
-                #'transient--do-replace
-              (or (oref transient--prefix transient-suffix)
-                  #'transient--do-exit)))))))
+            (pcase (list kind default return)
+              (`(prefix ,(or 'transient--do-stay 'transient--do-call) ,_)
+               #'transient--do-recurse)
+              (`(prefix   t ,_) #'transient--do-recurse)
+              (`(prefix  ,_ ,_) #'transient--do-stack)
+              (`(infix   ,_ ,_) #'transient--do-stay)
+              (`(suffix   t ,_) #'transient--do-call)
+              ('(suffix nil  t) #'transient--do-return)
+              (`(suffix nil ,_) #'transient--do-exit)
+              (`(suffix ,do ,_) do)))))))
     map))
 
 (defun transient--make-redisplay-map ()
   (setq transient--redisplay-key
-        (cl-case this-command
-          (transient-update
+        (pcase this-command
+          ('transient-update
            (setq transient--showp t)
            (setq unread-command-events
                  (listify-key-sequence (this-single-command-raw-keys))))
-          (transient-quit-seq
+          ('transient-quit-seq
            (setq unread-command-events
                  (butlast (listify-key-sequence
                            (this-single-command-raw-keys))
                           2))
            (butlast transient--redisplay-key))
-          (t nil)))
+          (_ nil)))
   (let ((topmap (make-sparse-keymap))
         (submap (make-sparse-keymap)))
     (when transient--redisplay-key
@@ -1786,7 +1923,7 @@ EDIT may be non-nil."
       (setq params (list :scope (oref transient--prefix scope))))
      (transient--prefix
       ;; Invoked as a ":transient-non-suffix 'transient--do-{stay,call}"
-      ;; of an outer prefix.  Unlike the usual `transient--do-replace',
+      ;; of an outer prefix.  Unlike the usual `transient--do-stack',
       ;; these predicates fail to clean up after the outer prefix.
       (transient--pop-keymap 'transient--transient-map)
       (transient--pop-keymap 'transient--redisplay-map))
@@ -1797,10 +1934,8 @@ EDIT may be non-nil."
       ;; Returning from help to edit.
       (setq transient--editp t)))
     (transient--init-objects name layout params)
+    (transient--init-keymaps)
     (transient--history-init transient--prefix)
-    (setq transient--predicate-map (transient--make-predicate-map))
-    (setq transient--transient-map (transient--make-transient-map))
-    (setq transient--redisplay-map (transient--make-redisplay-map))
     (setq transient--original-window (selected-window))
     (setq transient--original-buffer (current-buffer))
     (setq transient--minibuffer-depth (minibuffer-depth))
@@ -1817,8 +1952,16 @@ value.  Otherwise return CHILDREN as is."
       (funcall (oref group setup-children) children)
     children))
 
-(defun transient--init-objects (name layout params)
-  (setq transient--prefix (transient--init-prefix name params))
+(defun transient--init-keymaps ()
+  (setq transient--predicate-map (transient--make-predicate-map))
+  (setq transient--transient-map (transient--make-transient-map))
+  (setq transient--redisplay-map (transient--make-redisplay-map)))
+
+(defun transient--init-objects (&optional name layout params)
+  (if name
+      (setq transient--prefix (transient--init-prefix name params))
+    (setq name (oref transient--prefix command)))
+  (setq transient--refreshp (oref transient--prefix refresh-suffixes))
   (setq transient--layout (or layout (transient--init-suffixes name)))
   (setq transient--suffixes (transient--flatten-suffixes transient--layout)))
 
@@ -1845,10 +1988,11 @@ value.  Otherwise return CHILDREN as is."
   (cl-labels ((s (def)
                 (cond
                  ((stringp def) nil)
+                 ((cl-typep def 'transient-information) nil)
                  ((listp def) (cl-mapcan #'s def))
-                 ((transient-group--eieio-childp def)
+                 ((cl-typep def 'transient-group)
                   (cl-mapcan #'s (oref def suffixes)))
-                 ((transient-suffix--eieio-childp def)
+                 ((cl-typep def 'transient-suffix)
                   (list def)))))
     (cl-mapcan #'s layout)))
 
@@ -1860,31 +2004,37 @@ value.  Otherwise return CHILDREN as is."
 
 (defun transient--init-group (levels spec)
   (pcase-let ((`(,level ,class ,args ,children) (append spec nil)))
-    (when-let* ((- (transient--use-level-p level))
-                (obj (apply class :level level args))
-                (- (transient--use-suffix-p obj))
-                (suffixes (cl-mapcan (lambda (c) (transient--init-child levels 
c))
-                                     (transient-setup-children obj children))))
-      ;; Cannot use and-let* because of debbugs#31840.
-      (oset obj suffixes suffixes)
-      (list obj))))
+    (and-let* ((- (transient--use-level-p level))
+               (obj (apply class :level level args))
+               (- (transient--use-suffix-p obj))
+               (suffixes (cl-mapcan (lambda (c) (transient--init-child levels 
c))
+                                    (transient-setup-children obj children))))
+      (progn ; work around debbugs#31840
+        (oset obj suffixes suffixes)
+        (list obj)))))
 
 (defun transient--init-suffix (levels spec)
   (pcase-let* ((`(,level ,class ,args) spec)
                (cmd (plist-get args :command))
-               (level (or (alist-get cmd levels) level)))
+               (key (transient--kbd (plist-get args :key)))
+               (level (or (alist-get (cons cmd key) levels nil nil #'equal)
+                          (alist-get cmd levels)
+                          level)))
     (let ((fn (and (symbolp cmd)
                    (symbol-function cmd))))
       (when (autoloadp fn)
         (transient--debug "   autoload %s" cmd)
         (autoload-do-load fn)))
     (when (transient--use-level-p level)
-      (unless (and cmd (symbolp cmd))
-        (error "BUG: Non-symbolic suffix command: %s" cmd))
-      (let ((obj (if-let ((proto (get cmd 'transient--suffix)))
-                     (apply #'clone proto :level level args)
-                   (apply class :command cmd :level level args))))
-        (cond ((commandp cmd))
+      (let ((obj (if (child-of-class-p class 'transient-information)
+                     (apply class :level level args)
+                   (unless (and cmd (symbolp cmd))
+                     (error "BUG: Non-symbolic suffix command: %s" cmd))
+                   (if-let ((proto (and cmd (transient--suffix-prototype 
cmd))))
+                       (apply #'clone proto :level level args)
+                     (apply class :command cmd :level level args)))))
+        (cond ((not cmd))
+              ((commandp cmd))
               ((or (cl-typep obj 'transient-switch)
                    (cl-typep obj 'transient-option))
                ;; As a temporary special case, if the package was compiled
@@ -1893,7 +2043,8 @@ value.  Otherwise return CHILDREN as is."
                (defalias cmd #'transient--default-infix-command))
               ((transient--use-suffix-p obj)
                (error "Suffix command %s is not defined or autoloaded" cmd)))
-        (transient--init-suffix-key obj)
+        (unless (cl-typep obj 'transient-information)
+          (transient--init-suffix-key obj))
         (when (transient--use-suffix-p obj)
           (if (transient--inapt-suffix-p obj)
               (oset obj inapt t)
@@ -1917,33 +2068,38 @@ value.  Otherwise return CHILDREN as is."
         (error "No key for %s" (oref obj command))))))
 
 (defun transient--use-level-p (level &optional edit)
-  (or (and transient--editp (not edit))
+  (or transient--all-levels-p
+      (and transient--editp (not edit))
       (and (>= level 1)
            (<= level (oref transient--prefix level)))))
 
 (defun transient--use-suffix-p (obj)
-  (transient--do-suffix-p
-   (oref obj if)
-   (oref obj if-not)
-   (oref obj if-nil)
-   (oref obj if-non-nil)
-   (oref obj if-mode)
-   (oref obj if-not-mode)
-   (oref obj if-derived)
-   (oref obj if-not-derived)
-   t))
+  (let ((transient--shadowed-buffer (current-buffer))
+        (transient--pending-suffix obj))
+    (transient--do-suffix-p
+     (oref obj if)
+     (oref obj if-not)
+     (oref obj if-nil)
+     (oref obj if-non-nil)
+     (oref obj if-mode)
+     (oref obj if-not-mode)
+     (oref obj if-derived)
+     (oref obj if-not-derived)
+     t)))
 
 (defun transient--inapt-suffix-p (obj)
-  (transient--do-suffix-p
-   (oref obj inapt-if)
-   (oref obj inapt-if-not)
-   (oref obj inapt-if-nil)
-   (oref obj inapt-if-non-nil)
-   (oref obj inapt-if-mode)
-   (oref obj inapt-if-not-mode)
-   (oref obj inapt-if-derived)
-   (oref obj inapt-if-not-derived)
-   nil))
+  (let ((transient--shadowed-buffer (current-buffer))
+        (transient--pending-suffix obj))
+    (transient--do-suffix-p
+     (oref obj inapt-if)
+     (oref obj inapt-if-not)
+     (oref obj inapt-if-nil)
+     (oref obj inapt-if-non-nil)
+     (oref obj inapt-if-mode)
+     (oref obj inapt-if-not-mode)
+     (oref obj inapt-if-derived)
+     (oref obj inapt-if-not-derived)
+     nil)))
 
 (defun transient--do-suffix-p
     (if if-not if-nil if-non-nil if-mode if-not-mode if-derived if-not-derived
@@ -1959,14 +2115,15 @@ value.  Otherwise return CHILDREN as is."
    (if-not-mode    (not (if (atom if-not-mode)
                             (eq major-mode if-not-mode)
                           (memq major-mode if-not-mode))))
-   (if-derived          (if (or (atom if-derived) (>= emacs-major-version 30))
+   (if-derived          (if (or (atom if-derived)
+                                (>= emacs-major-version 30))
                             (derived-mode-p if-derived)
                           (apply #'derived-mode-p if-derived)))
    (if-not-derived (not (if (or (atom if-not-derived)
                                 (>= emacs-major-version 30))
                             (derived-mode-p if-not-derived)
                           (apply #'derived-mode-p if-not-derived))))
-   (t default)))
+   (default)))
 
 (defun transient--suffix-predicate (spec)
   (let ((plist (nth 2 spec)))
@@ -1997,6 +2154,17 @@ value.  Otherwise return CHILDREN as is."
     ;; that we just added.
     (setq transient--exitp 'replace)))
 
+(defun transient--refresh-transient ()
+  (transient--debug 'refresh-transient)
+  (transient--pop-keymap 'transient--predicate-map)
+  (transient--pop-keymap 'transient--transient-map)
+  (transient--pop-keymap 'transient--redisplay-map)
+  (transient--init-objects)
+  (transient--init-keymaps)
+  (transient--push-keymap 'transient--transient-map)
+  (transient--push-keymap 'transient--redisplay-map)
+  (transient--redisplay))
+
 (defun transient--pre-command ()
   (transient--debug 'pre-command)
   (transient--with-emergency-exit
@@ -2005,8 +2173,8 @@ value.  Otherwise return CHILDREN as is."
     ;; lead to a suffix being remapped to a non-suffix.  We have to undo
     ;; the remapping in that case.  However, remapping a non-suffix to
     ;; another should remain possible.
-    (when (and (transient--get-predicate-for this-original-command 'suffix)
-               (not (transient--get-predicate-for this-command 'suffix)))
+    (when (and (transient--get-pre-command this-original-command 'suffix)
+               (not (transient--get-pre-command this-command 'suffix)))
       (setq this-command this-original-command))
     (cond
      ((memq this-command '(transient-update transient-quit-seq))
@@ -2030,34 +2198,11 @@ value.  Otherwise return CHILDREN as is."
       (transient--wrap-command))
      (t
       (setq transient--exitp nil)
-      (let ((exitp (eq (transient--do-pre-command) transient--exit)))
+      (let ((exitp (eq (transient--call-pre-command) transient--exit)))
         (transient--wrap-command)
         (when exitp
           (transient--pre-exit)))))))
 
-(defun transient--do-pre-command ()
-  (if-let ((fn (transient--get-predicate-for this-command)))
-      (let ((action (funcall fn)))
-        (when (eq action transient--exit)
-          (setq transient--exitp (or transient--exitp t)))
-        action)
-    (if (let ((keys (this-command-keys-vector)))
-          (eq (aref keys (1- (length keys))) ?\C-g))
-        (setq this-command 'transient-noop)
-      (unless (transient--edebug-command-p)
-        (setq this-command 'transient-undefined)))
-    transient--stay))
-
-(defun transient--get-predicate-for (cmd &optional suffix-only)
-  (or (ignore-errors
-        (lookup-key transient--predicate-map (vector cmd)))
-      (and (not suffix-only)
-           (let ((pred (oref transient--prefix transient-non-suffix)))
-             (pcase pred
-               ('t   #'transient--do-stay)
-               ('nil #'transient--do-warn)
-               (_    pred))))))
-
 (defun transient--pre-exit ()
   (transient--debug 'pre-exit)
   (transient--delete-window)
@@ -2086,8 +2231,9 @@ value.  Otherwise return CHILDREN as is."
            (and (minibuffer-selected-window)
                 (selected-window)))
           (buf (window-buffer transient--window)))
-      ;; Only delete the window if it never showed another buffer.
-      (unless (eq (car (window-parameter transient--window 'quit-restore)) 
'other)
+      ;; Only delete the window if it has never shown another buffer.
+      (unless (eq (car (window-parameter transient--window 'quit-restore))
+                  'other)
         (with-demoted-errors "Error while exiting transient: %S"
           (delete-window transient--window)))
       (kill-buffer buf)
@@ -2163,66 +2309,65 @@ value.  Otherwise return CHILDREN as is."
              (remove-hook 'minibuffer-exit-hook ,exit)))
        ,@body)))
 
-(defun transient--wrap-command ()
-  (if (>= emacs-major-version 30)
-      (transient--wrap-command-30)
-    (transient--wrap-command-29)))
-
-(defun transient--wrap-command-30 ()
-  (letrec
-      ((prefix transient--prefix)
-       (suffix this-command)
-       (advice (lambda (fn &rest args)
-                 (interactive
-                  (lambda (spec)
-                    (let ((abort t))
-                      (unwind-protect
-                         (prog1 (advice-eval-interactive-spec spec)
-                           (setq abort nil))
-                       (when abort
-                          (when-let ((unwind (oref prefix unwind-suffix)))
-                            (transient--debug 'unwind-interactive)
-                            (funcall unwind suffix))
-                          (advice-remove suffix advice)
-                          (oset prefix unwind-suffix nil))))))
-                 (unwind-protect
-                     (apply fn args)
-                   (when-let ((unwind (oref prefix unwind-suffix)))
-                     (transient--debug 'unwind-command)
-                     (funcall unwind suffix))
-                   (advice-remove suffix advice)
-                   (oset prefix unwind-suffix nil)))))
-    (advice-add suffix :around advice '((depth . -99)))))
-
-(defun transient--wrap-command-29 ()
-  (let* ((prefix transient--prefix)
-         (suffix this-command)
-         (advice nil)
-         (advice-interactive
-          (lambda (spec)
-            (let ((abort t))
+(static-if (>= emacs-major-version 30)
+    (defun transient--wrap-command ()
+      (cl-assert
+       (>= emacs-major-version 30) nil
+       "Emacs was downgraded, making it necessary to recompile Transient")
+      (letrec
+          ((prefix transient--prefix)
+           (suffix this-command)
+           (advice (lambda (fn &rest args)
+                     (interactive
+                      (lambda (spec)
+                        (let ((abort t))
+                          (unwind-protect
+                              (prog1 (advice-eval-interactive-spec spec)
+                                (setq abort nil))
+                            (when abort
+                              (when-let ((unwind (oref prefix unwind-suffix)))
+                                (transient--debug 'unwind-interactive)
+                                (funcall unwind suffix))
+                              (advice-remove suffix advice)
+                              (oset prefix unwind-suffix nil))))))
+                     (unwind-protect
+                         (apply fn args)
+                       (when-let ((unwind (oref prefix unwind-suffix)))
+                         (transient--debug 'unwind-command)
+                         (funcall unwind suffix))
+                       (advice-remove suffix advice)
+                       (oset prefix unwind-suffix nil)))))
+        (advice-add suffix :around advice '((depth . -99)))))
+
+  (defun transient--wrap-command ()
+    (let* ((prefix transient--prefix)
+           (suffix this-command)
+           (advice nil)
+           (advice-interactive
+            (lambda (spec)
+              (let ((abort t))
+                (unwind-protect
+                    (prog1 (advice-eval-interactive-spec spec)
+                      (setq abort nil))
+                  (when abort
+                    (when-let ((unwind (oref prefix unwind-suffix)))
+                      (transient--debug 'unwind-interactive)
+                      (funcall unwind suffix))
+                    (advice-remove suffix advice)
+                    (oset prefix unwind-suffix nil))))))
+           (advice-body
+            (lambda (fn &rest args)
               (unwind-protect
-                 (prog1 (advice-eval-interactive-spec spec)
-                   (setq abort nil))
-               (when abort
-                  (when-let ((unwind (oref prefix unwind-suffix)))
-                    (transient--debug 'unwind-interactive)
-                    (funcall unwind suffix))
-                  (advice-remove suffix advice)
-                  (oset prefix unwind-suffix nil))))))
-         (advice-body
-          (lambda (fn &rest args)
-            (unwind-protect
-                (apply fn args)
-              (when-let ((unwind (oref prefix unwind-suffix)))
-                (transient--debug 'unwind-command)
-                (funcall unwind suffix))
-              (advice-remove suffix advice)
-              (oset prefix unwind-suffix nil)))))
-    (setq advice `(lambda (fn &rest args)
-                    (interactive ,advice-interactive)
-                    (apply ',advice-body fn args)))
-    (advice-add suffix :around advice '((depth . -99)))))
+                  (apply fn args)
+                (when-let ((unwind (oref prefix unwind-suffix)))
+                  (transient--debug 'unwind-command)
+                  (funcall unwind suffix))
+                (advice-remove suffix advice)
+                (oset prefix unwind-suffix nil)))))
+      (setq advice `(lambda (fn &rest args)
+                      (interactive ,advice-interactive)
+                      (apply ',advice-body fn args)))
+      (advice-add suffix :around advice '((depth . -99))))))
 
 (defun transient--premature-post-command ()
   (and (equal (this-command-keys-vector) [])
@@ -2243,7 +2388,21 @@ value.  Otherwise return CHILDREN as is."
     (transient--debug 'post-command)
     (transient--with-emergency-exit
       (cond (transient--exitp (transient--post-exit))
-            ((eq this-command (oref transient--prefix command)))
+            ;; If `this-command' is the current transient prefix, then we
+            ;; have already taken care of updating the transient buffer...
+            ((and (eq this-command (oref transient--prefix command))
+                  ;; ... but if `prefix-arg' is non-nil, then the values
+                  ;; of `this-command' and `real-this-command' are untrue
+                  ;; because `prefix-command-preserve-state' changes them.
+                  ;; We cannot use `current-prefix-arg' because it is set
+                  ;; too late (in `command-execute'), and if it were set
+                  ;; earlier, then we likely still would not be able to
+                  ;; rely on it and `prefix-command-preserve-state-hook'
+                  ;; would have to be used to record that a universal
+                  ;; argument is in effect.
+                  (not prefix-arg)))
+            (transient--refreshp
+             (transient--refresh-transient))
             ((let ((old transient--redisplay-map)
                    (new (transient--make-redisplay-map)))
                (unless (equal old new)
@@ -2283,6 +2442,7 @@ value.  Otherwise return CHILDREN as is."
     (setq transient--exitp nil)
     (setq transient--helpp nil)
     (setq transient--editp nil)
+    (setq transient--all-levels-p nil)
     (setq transient--minibuffer-depth 0)
     (run-hooks 'transient-exit-hook)
     (when resume
@@ -2293,6 +2453,7 @@ value.  Otherwise return CHILDREN as is."
   (push (list (oref transient--prefix command)
               transient--layout
               transient--editp
+              :transient-suffix (oref transient--prefix transient-suffix)
               :scope (oref transient--prefix scope))
         transient--stack))
 
@@ -2353,12 +2514,12 @@ value.  Otherwise return CHILDREN as is."
                           (concat ", " (apply #'format args)))
                          (args
                           (concat ", " (apply (car args) (cdr args))))
-                         (t "")))
+                         ("")))
         (apply #'message arg args)))))
 
 (defun transient--emergency-exit ()
   "Exit the current transient command after an error occurred.
-When no transient is active (i.e. when `transient--prefix' is
+When no transient is active (i.e., when `transient--prefix' is
 nil) then do nothing."
   (transient--debug 'emergency-exit)
   (when transient--prefix
@@ -2369,6 +2530,36 @@ nil) then do nothing."
 
 ;;; Pre-Commands
 
+(defun transient--call-pre-command ()
+  (if-let ((fn (transient--get-pre-command this-command)))
+      (let ((action (funcall fn)))
+        (when (eq action transient--exit)
+          (setq transient--exitp (or transient--exitp t)))
+        action)
+    (if (let ((keys (this-command-keys-vector)))
+          (eq (aref keys (1- (length keys))) ?\C-g))
+        (setq this-command 'transient-noop)
+      (unless (transient--edebug-command-p)
+        (setq this-command 'transient-undefined)))
+    transient--stay))
+
+(defun transient--get-pre-command (&optional cmd enforce-type)
+  (or (and (not (eq enforce-type 'non-suffix))
+           (lookup-key transient--predicate-map (vector cmd)))
+      (and (not (eq enforce-type 'suffix))
+           (transient--resolve-pre-command
+            (oref transient--prefix transient-non-suffix)
+            t))))
+
+(defun transient--resolve-pre-command (pre &optional resolve-boolean)
+  (cond ((booleanp pre)
+         (if resolve-boolean
+             (if pre #'transient--do-stay #'transient--do-warn)
+           pre))
+        ((string-match-p "--do-" (symbol-name pre)) pre)
+        ((let ((sym (intern (format "transient--do-%s" pre))))
+           (if (functionp sym) sym pre)))))
+
 (defun transient--do-stay ()
   "Call the command without exporting variables and stay transient."
   transient--stay)
@@ -2409,7 +2600,8 @@ If there is no parent prefix, then behave like 
`transient--do-exit'."
 
 (defun transient--do-leave ()
   "Call the command without exporting variables and exit the transient."
-  transient--stay)
+  (transient--stack-zap)
+  transient--exit)
 
 (defun transient--do-push-button ()
   "Call the command represented by the activated button.
@@ -2424,26 +2616,35 @@ Use that command's pre-command to determine transient 
behavior."
                                    (posn-point (event-start 
last-command-event))
                                  (point))
                                'command)))
-    (transient--do-pre-command)))
+    (transient--call-pre-command)))
 
 (defun transient--do-recurse ()
   "Call the transient prefix command, preparing for return to active transient.
 If there is no parent prefix, then just call the command."
-  (transient--do-replace))
+  (transient--do-stack))
 
 (defun transient--setup-recursion (prefix-obj)
   (when transient--stack
     (let ((command (oref prefix-obj command)))
       (when-let ((suffix-obj (transient-suffix-object command)))
-        (when (and (slot-boundp suffix-obj 'transient)
-                   (memq (oref suffix-obj transient)
-                         (list t #'transient--do-recurse)))
-          (oset prefix-obj transient-suffix 'transient--do-return))))))
+        (when (memq (if (slot-boundp suffix-obj 'transient)
+                        (oref suffix-obj transient)
+                      (oref transient-current-prefix transient-suffix))
+                    (list t #'transient--do-recurse))
+          (oset prefix-obj transient-suffix t))))))
+
+(defun transient--do-stack ()
+  "Call the transient prefix command, stacking the active transient.
+Push the active transient to the transient stack."
+  (transient--export)
+  (transient--stack-push)
+  (setq transient--exitp 'replace)
+  transient--exit)
 
 (defun transient--do-replace ()
-  "Call the transient prefix command, replacing the active transient."
+  "Call the transient prefix command, replacing the active transient.
+Do not push the active transient to the transient stack."
   (transient--export)
-  (transient--stack-push)
   (setq transient--exitp 'replace)
   transient--exit)
 
@@ -2462,7 +2663,9 @@ If there is no parent prefix, then just call the command."
          (setq transient--editp nil)
          (transient-setup)
          transient--stay)
-        (t transient--exit)))
+        (prefix-arg
+         transient--stay)
+        (transient--exit)))
 
 (defun transient--do-quit-all ()
   "Exit all transients without saving the transient stack."
@@ -2474,7 +2677,7 @@ If there is no parent prefix, then just call the command."
 In that case behave like `transient--do-stay', otherwise similar
 to `transient--do-warn'."
   (unless transient-enable-popup-navigation
-    (setq this-command 'transient-popup-navigation-help))
+    (setq this-command 'transient-inhibit-move))
   transient--stay)
 
 (defun transient--do-minus ()
@@ -2485,22 +2688,27 @@ prefix argument and pivot to `transient-update'."
     (setq this-command 'transient-update))
   transient--stay)
 
-(put 'transient--do-stay       'transient-color 'transient-red)
-(put 'transient--do-noop       'transient-color 'transient-red)
-(put 'transient--do-warn       'transient-color 'transient-red)
-(put 'transient--do-warn-inapt 'transient-color 'transient-red)
-(put 'transient--do-call       'transient-color 'transient-red)
-(put 'transient--do-return     'transient-color 'transient-purple)
-(put 'transient--do-exit       'transient-color 'transient-blue)
-(put 'transient--do-recurse    'transient-color 'transient-red)
-(put 'transient--do-replace    'transient-color 'transient-blue)
-(put 'transient--do-suspend    'transient-color 'transient-blue)
-(put 'transient--do-quit-one   'transient-color 'transient-blue)
-(put 'transient--do-quit-all   'transient-color 'transient-blue)
-(put 'transient--do-move       'transient-color 'transient-red)
-(put 'transient--do-minus      'transient-color 'transient-red)
+(put 'transient--do-stay       'transient-face 'transient-key-stay)
+(put 'transient--do-noop       'transient-face 'transient-key-noop)
+(put 'transient--do-warn       'transient-face 'transient-key-noop)
+(put 'transient--do-warn-inapt 'transient-face 'transient-key-noop)
+(put 'transient--do-call       'transient-face 'transient-key-stay)
+(put 'transient--do-return     'transient-face 'transient-key-return)
+(put 'transient--do-exit       'transient-face 'transient-key-exit)
+(put 'transient--do-leave      'transient-face 'transient-key-exit)
+
+(put 'transient--do-recurse    'transient-face 'transient-key-stay)
+(put 'transient--do-stack      'transient-face 'transient-key-stay)
+(put 'transient--do-replace    'transient-face 'transient-key-exit)
+(put 'transient--do-suspend    'transient-face 'transient-key-exit)
+
+(put 'transient--do-quit-one   'transient-face 'transient-key-return)
+(put 'transient--do-quit-all   'transient-face 'transient-key-exit)
+(put 'transient--do-move       'transient-face 'transient-key-stay)
+(put 'transient--do-minus      'transient-face 'transient-key-stay)
 
 ;;; Commands
+;;;; Noop
 
 (defun transient-noop ()
   "Do nothing at all."
@@ -2539,27 +2747,23 @@ prefix argument and pivot to `transient-update'."
     (other-window 1)
     (display-warning 'transient "Inconsistent transient state detected.
 This should never happen.
-Please open an issue and post the shown command log.
-This is a heisenbug, so any additional details might help.
-Thanks!" :error)))
+Please open an issue and post the shown command log." :error)))
 
-(defun transient-toggle-common ()
-  "Toggle whether common commands are always shown."
+(defun transient-inhibit-move ()
+  "Warn the user that popup navigation is disabled."
   (interactive)
-  (setq transient-show-common-commands (not transient-show-common-commands)))
+  (message "To enable use of `%s', please customize `%s'"
+           this-original-command
+           'transient-enable-popup-navigation))
 
-(defun transient-suspend ()
-  "Suspend the current transient.
-It can later be resumed using `transient-resume' while no other
-transient is active."
-  (interactive))
+;;;; Core
 
 (defun transient-quit-all ()
   "Exit all transients without saving the transient stack."
   (interactive))
 
 (defun transient-quit-one ()
-  "Exit the current transients, possibly returning to the previous."
+  "Exit the current transients, returning to outer transient, if any."
   (interactive))
 
 (defun transient-quit-seq ()
@@ -2569,17 +2773,48 @@ transient is active."
 (defun transient-update ()
   "Redraw the transient's state in the popup buffer."
   (interactive)
-  (when (equal this-original-command 'negative-argument)
-    (setq prefix-arg current-prefix-arg)))
+  (setq prefix-arg current-prefix-arg))
 
 (defun transient-show ()
   "Show the transient's state in the popup buffer."
   (interactive)
   (setq transient--showp t))
 
-(defvar-local transient--restore-winconf nil)
+(defun transient-push-button ()
+  "Invoke the suffix command represented by this button."
+  (interactive))
 
-(defvar transient-resume-mode)
+;;;; Suspend
+
+(defun transient-suspend ()
+  "Suspend the current transient.
+It can later be resumed using `transient-resume', while no other
+transient is active."
+  (interactive))
+
+(define-minor-mode transient-resume-mode
+  "Auxiliary minor-mode used to resume a transient after viewing help.")
+
+(defun transient-resume ()
+  "Resume a previously suspended stack of transients."
+  (interactive)
+  (cond (transient--stack
+         (let ((winconf transient--restore-winconf))
+           (kill-local-variable 'transient--restore-winconf)
+           (when transient-resume-mode
+             (transient-resume-mode -1)
+             (quit-window))
+           (when winconf
+             (set-window-configuration winconf)))
+         (transient--stack-pop))
+        (transient-resume-mode
+         (kill-local-variable 'transient--restore-winconf)
+         (transient-resume-mode -1)
+         (quit-window))
+        (t
+         (message "No suspended transient command"))))
+
+;;;; Help
 
 (defun transient-help (&optional interactive)
   "Show help for the active transient or one of its suffixes.\n\n(fn)"
@@ -2596,12 +2831,15 @@ transient is active."
                transient--prefix
              (or (transient-suffix-object)
                  this-original-command)))
-          (setq transient--restore-winconf winconf))
+          (setq-local transient--restore-winconf winconf))
         (fit-window-to-buffer nil (frame-height) (window-height))
         (transient-resume-mode)
-        (message "Type \"q\" to resume transient command.")
+        (message (substitute-command-keys
+                  "Type \\`q' to resume transient command."))
         t))))
 
+;;;; Level
+
 (defun transient-set-level (&optional command level)
   "Set the level of the transient or one of its suffix commands."
   (interactive
@@ -2613,10 +2851,9 @@ transient is active."
           (list command
                 (let ((keys (this-single-command-raw-keys)))
                   (and (lookup-key transient--transient-map keys)
-                       (string-to-number
-                        (let ((transient--active-infix
-                               (transient-suffix-object command)))
-                          (transient--show)
+                       (progn
+                         (transient--show)
+                         (string-to-number
                           (transient--read-number-N
                            (format "Set level for `%s': " command)
                            nil nil (not (eq command prefix)))))))))))
@@ -2627,32 +2864,64 @@ transient is active."
    (level
     (let* ((prefix (oref transient--prefix command))
            (alist (alist-get prefix transient-levels))
-           (sym command))
-      (if (eq command prefix)
-          (progn (oset transient--prefix level level)
-                 (setq sym t))
-        (oset (transient-suffix-object command) level level))
-      (setf (alist-get sym alist) level)
+           (akey command))
+      (cond ((eq command prefix)
+             (oset transient--prefix level level)
+             (setq akey t))
+            (t
+             (oset (transient-suffix-object command) level level)
+             (when (cdr (cl-remove-if-not (lambda (obj)
+                                            (eq (oref obj command) command))
+                                          transient--suffixes))
+               (setq akey (cons command (this-command-keys))))))
+      (setf (alist-get akey alist) level)
       (setf (alist-get prefix transient-levels) alist))
     (transient-save-levels)
     (transient--show))
    (t
     (transient-undefined))))
 
+(transient-define-suffix transient-toggle-level-limit ()
+  "Toggle whether to temporarily displayed suffixes on all levels."
+  :description
+  (lambda ()
+    (cond
+     ((= transient-default-level transient--max-level)
+      "Always displaying all levels")
+     (transient--all-levels-p
+      (format "Hide suffix %s"
+              (propertize
+               (format "levels > %s" (oref (transient-prefix-object) level))
+               'face 'transient-higher-level)))
+     ("Show all suffix levels")))
+  :inapt-if (lambda () (= transient-default-level transient--max-level))
+  :transient t
+  (interactive)
+  (setq transient--all-levels-p (not transient--all-levels-p))
+  (setq transient--refreshp t))
+
+;;;; Value
+
 (defun transient-set ()
-  "Save the value of the active transient for this Emacs session."
+  "Set active transient's value for this Emacs session."
   (interactive)
-  (transient-set-value (or transient--prefix transient-current-prefix)))
+  (transient-set-value (transient-prefix-object)))
+
+(defalias 'transient-set-and-exit 'transient-set
+  "Set active transient's value for this Emacs session and exit.")
 
 (defun transient-save ()
-  "Save the value of the active transient persistenly across Emacs sessions."
+  "Save active transient's value for this and future Emacs sessions."
   (interactive)
-  (transient-save-value (or transient--prefix transient-current-prefix)))
+  (transient-save-value (transient-prefix-object)))
+
+(defalias 'transient-save-and-exit 'transient-save
+  "Save active transient's value for this and future Emacs sessions and exit.")
 
 (defun transient-reset ()
   "Clear the set and saved values of the active transient."
   (interactive)
-  (transient-reset-value (or transient--prefix transient-current-prefix)))
+  (transient-reset-value (transient-prefix-object)))
 
 (defun transient-history-next ()
   "Switch to the next value used for the active transient."
@@ -2679,44 +2948,36 @@ transient is active."
       (oset obj value (nth pos hst))
       (mapc #'transient-init-value transient--suffixes))))
 
-(defun transient-scroll-up (&optional arg)
-  "Scroll text of transient popup window upward ARG lines.
-If ARG is nil scroll near full screen.  This is a wrapper
-around `scroll-up-command' (which see)."
-  (interactive "^P")
-  (with-selected-window transient--window
-    (scroll-up-command arg)))
-
-(defun transient-scroll-down (&optional arg)
-  "Scroll text of transient popup window down ARG lines.
-If ARG is nil scroll near full screen.  This is a wrapper
-around `scroll-down-command' (which see)."
-  (interactive "^P")
-  (with-selected-window transient--window
-    (scroll-down-command arg)))
+;;;; Auxiliary
 
-(defun transient-push-button ()
-  "Invoke the suffix command represented by this button."
-  (interactive))
+(defun transient-toggle-common ()
+  "Toggle whether common commands are permanently shown."
+  (interactive)
+  (setq transient-show-common-commands (not transient-show-common-commands)))
 
-(defun transient-resume ()
-  "Resume a previously suspended stack of transients."
+(defun transient-toggle-debug ()
+  "Toggle debugging statements for transient commands."
   (interactive)
-  (cond (transient--stack
-         (let ((winconf transient--restore-winconf))
-           (kill-local-variable 'transient--restore-winconf)
-           (when transient-resume-mode
-             (transient-resume-mode -1)
-             (quit-window))
-           (when winconf
-             (set-window-configuration winconf)))
-         (transient--stack-pop))
-        (transient-resume-mode
-         (kill-local-variable 'transient--restore-winconf)
-         (transient-resume-mode -1)
-         (quit-window))
-        (t
-         (message "No suspended transient command"))))
+  (setq transient--debug (not transient--debug))
+  (message "Debugging transient %s"
+           (if transient--debug "enabled" "disabled")))
+
+(transient-define-suffix transient-echo-arguments (arguments)
+  "Show the transient's active ARGUMENTS in the echo area.
+Intended for use in prefixes used for demonstration purposes,
+such as when suggesting a new feature or reporting an issue."
+  :transient t
+  :description "Echo arguments"
+  :key "x"
+  (interactive (list (transient-args transient-current-command)))
+  (message "%s: %s"
+           (key-description (this-command-keys))
+           (mapconcat (lambda (arg)
+                        (propertize (if (string-match-p " " arg)
+                                        (format "%S" arg)
+                                      arg)
+                                    'face 'transient-argument))
+                      arguments " ")))
 
 ;;; Value
 ;;;; Init
@@ -2822,28 +3083,18 @@ user using the reader specified by the `reader' slot 
(using the
 `transient-infix' method described below).
 
 For some infix classes the value is changed without reading
-anything in the minibuffer, i.e. the mere act of invoking the
+anything in the minibuffer, i.e., the mere act of invoking the
 infix command determines what the new value should be, based
 on the previous value.")
 
 (cl-defmethod transient-infix-read :around ((obj transient-infix))
-  "Highlight the infix in the popup buffer.
+  "Refresh the transient buffer buffer calling the next method.
 
-This also wraps the call to `cl-call-next-method' with two
-macros.
-
-`transient--with-suspended-override' is necessary to allow
-reading user input using the minibuffer.
-
-`transient--with-emergency-exit' arranges for the transient to
-be exited in case of an error because otherwise Emacs would get
-stuck in an inconsistent state, which might make it necessary to
-kill it from the outside.
-
-If you replace this method, then you must make sure to always use
-the latter macro and most likely also the former."
-  (let ((transient--active-infix obj))
-    (transient--show))
+Also wrap `cl-call-next-method' with two macros:
+- `transient--with-suspended-override' allows use of minibuffer.
+- `transient--with-emergency-exit' arranges for the transient to
+  be exited in case of an error."
+  (transient--show)
   (transient--with-emergency-exit
     (transient--with-suspended-override
      (cl-call-next-method obj))))
@@ -2861,7 +3112,7 @@ the lack of history, for example.
 
 Only for very simple classes that toggle or cycle through a very
 limited number of possible values should you replace this with a
-simple method that does not handle history.  (E.g. for a command
+simple method that does not handle history.  (E.g., for a command
 line switch the only possible values are \"use it\" and \"don't use
 it\", in which case it is pointless to preserve history.)"
   (with-slots (value multi-value always-read allow-empty choices) obj
@@ -2872,6 +3123,7 @@ it\", in which case it is pointless to preserve history.)"
         (oset obj value nil)
       (let* ((enable-recursive-minibuffers t)
              (reader (oref obj reader))
+             (choices (if (functionp choices) (funcall choices) choices))
              (prompt (transient-prompt obj))
              (value (if multi-value (mapconcat #'identity value ",") value))
              (history-key (or (oref obj history-key)
@@ -2894,7 +3146,7 @@ it\", in which case it is pointless to preserve history.)"
                                           initial-input history))
                (choices
                 (completing-read prompt choices nil t initial-input history))
-               (t (read-string prompt initial-input history)))))
+               ((read-string prompt initial-input history)))))
         (cond ((and (equal value "") (not allow-empty))
                (setq value nil))
               ((and (equal value "\"\"") allow-empty)
@@ -2926,7 +3178,7 @@ The last value is \"don't use any of these switches\"."
 Use this if you want to share an infix's history with a regular
 stand-alone command."
   (cl-letf (((symbol-function #'transient--show) #'ignore))
-    (transient-infix-read (get command 'transient--suffix))))
+    (transient-infix-read (transient--suffix-prototype command))))
 
 ;;;; Readers
 
@@ -3017,8 +3269,6 @@ prompt."
 
 ;;;; Set
 
-(defvar transient--unset-incompatible t)
-
 (cl-defgeneric transient-infix-set (obj value)
   "Set the value of infix object OBJ to value.")
 
@@ -3026,29 +3276,32 @@ prompt."
   "Set the value of infix object OBJ to value."
   (oset obj value value))
 
-(cl-defmethod transient-infix-set :around ((obj transient-argument) value)
+(cl-defmethod transient-infix-set :after ((obj transient-argument) value)
   "Unset incompatible infix arguments."
-  (let ((arg (if (slot-boundp obj 'argument)
-                 (oref obj argument)
-               (oref obj argument-regexp))))
-    (if-let ((sic (and value arg transient--unset-incompatible))
-             (spec (oref transient--prefix incompatible))
-             (incomp (cl-mapcan (lambda (rule)
-                                  (and (member arg rule)
-                                       (remove arg rule)))
-                                spec)))
-        (progn
-          (cl-call-next-method obj value)
-          (dolist (arg incomp)
-            (when-let ((obj (cl-find-if
-                             (lambda (obj)
-                               (and (slot-exists-p obj 'argument)
-                                    (slot-boundp obj 'argument)
-                                    (equal (oref obj argument) arg)))
-                             transient--suffixes)))
-              (let ((transient--unset-incompatible nil))
-                (transient-infix-set obj nil)))))
-      (cl-call-next-method obj value))))
+  (when-let* ((--- value)
+              (val (transient-infix-value obj))
+              (arg (if (slot-boundp obj 'argument)
+                       (oref obj argument)
+                     (oref obj argument-format)))
+              (spec (oref transient--prefix incompatible))
+              (filter (lambda (x rule)
+                        (and (member x rule)
+                             (remove x rule))))
+              (incomp (nconc
+                       (cl-mapcan (apply-partially filter arg) spec)
+                       (and (not (equal val arg))
+                            (cl-mapcan (apply-partially filter val) spec)))))
+    (dolist (obj transient--suffixes)
+      (when-let* ((--- (cl-typep obj 'transient-argument))
+                  (val (transient-infix-value obj))
+                  (arg (if (slot-boundp obj 'argument)
+                           (oref obj argument)
+                         (oref obj argument-format)))
+                  (--- (if (equal val arg)
+                           (member arg incomp)
+                         (or (member val incomp)
+                             (member arg incomp)))))
+        (transient-infix-set obj nil)))))
 
 (cl-defgeneric transient-set-value (obj)
   "Set the value of the transient prefix OBJ.")
@@ -3111,11 +3364,11 @@ the set, saved or default value for PREFIX."
 
 (defun transient--get-wrapped-value (obj)
   (and-let* ((value (transient-infix-value obj)))
-    (cl-ecase (and (slot-exists-p obj 'multi-value)
-                   (oref obj multi-value))
-      ((nil)    (list value))
-      ((t rest) (list value))
-      (repeat   value))))
+    (pcase-exhaustive (and (slot-exists-p obj 'multi-value)
+                           (oref obj multi-value))
+      ('nil          (list value))
+      ((or 't 'rest) (list value))
+      ('repeat       value))))
 
 (cl-defgeneric transient-infix-value (obj)
   "Return the value of the suffix object OBJ.
@@ -3150,17 +3403,17 @@ does nothing." nil)
   "Return ARGUMENT and VALUE as a unit or nil if the latter is nil."
   (and-let* ((value (oref obj value)))
     (let ((arg (oref obj argument)))
-      (cl-ecase (oref obj multi-value)
-        ((nil)    (concat arg value))
-        ((t rest) (cons arg value))
-        (repeat   (mapcar (lambda (v) (concat arg v)) value))))))
+      (pcase-exhaustive (oref obj multi-value)
+        ('nil          (concat arg value))
+        ((or 't 'rest) (cons arg value))
+        ('repeat       (mapcar (lambda (v) (concat arg v)) value))))))
 
 (cl-defmethod transient-infix-value ((_   transient-variable))
   "Return nil, which means \"no value\".
 
 Setting the value of a variable is done by, well, setting the
-value of the variable.  I.e. this is a side-effect and does not
-contribute to the value of the transient."
+value of the variable.  I.e., this is a side-effect and does
+not contribute to the value of the transient."
   nil)
 
 ;;;; Utilities
@@ -3242,12 +3495,13 @@ have a history of their own.")
                    (list (propertize (oref suffix key) 'face 
'transient-key)))))
           transient--suffixes)
          #'string<)
-        (propertize "|" 'face 'transient-unreachable-key))))))
+        (propertize "|" 'face 'transient-delimiter))))))
 
 (defun transient--show ()
   (transient--timer-cancel)
   (setq transient--showp t)
-  (let ((buf (get-buffer-create transient--buffer-name))
+  (let ((transient--shadowed-buffer (current-buffer))
+        (buf (get-buffer-create transient--buffer-name))
         (focus nil))
     (with-current-buffer buf
       (when transient-enable-popup-navigation
@@ -3260,9 +3514,11 @@ have a history of their own.")
       (when (bound-and-true-p tab-line-format)
         (setq tab-line-format nil))
       (setq header-line-format nil)
-      (setq mode-line-format (if (eq transient-mode-line-format 'line)
-                                 nil
-                               transient-mode-line-format))
+      (setq mode-line-format
+            (if (or (natnump transient-mode-line-format)
+                    (eq transient-mode-line-format 'line))
+                nil
+              transient-mode-line-format))
       (setq mode-line-buffer-identification
             (symbol-name (oref transient--prefix command)))
       (if transient-enable-popup-navigation
@@ -3273,16 +3529,8 @@ have a history of their own.")
       (transient--insert-groups)
       (when (or transient--helpp transient--editp)
         (transient--insert-help))
-      (when (and (eq transient-mode-line-format 'line)
-                 window-system)
-        (let ((face
-               (if-let ((f (and (transient--semantic-coloring-p)
-                                (transient--prefix-color transient--prefix))))
-                   `(,@(and (>= emacs-major-version 27) '(:extend t))
-                     :background ,(face-foreground f))
-                 'transient-separator)))
-          (insert (propertize "__" 'face face 'display '(space :height (1))))
-          (insert (propertize "\n" 'face face 'line-height t))))
+      (when-let ((line (transient--separator-line)))
+        (insert line))
       (when transient-force-fixed-pitch
         (transient--force-fixed-pitch)))
     (unless (window-live-p transient--window)
@@ -3304,11 +3552,31 @@ have a history of their own.")
         (fit-window-to-buffer window nil (window-height window))
       (fit-window-to-buffer window nil 1))))
 
+(defun transient--separator-line ()
+  (and-let* ((height (cond ((not window-system) nil)
+                           ((natnump transient-mode-line-format)
+                            transient-mode-line-format)
+                           ((eq transient-mode-line-format 'line) 1)))
+             (face `(,@(and (>= emacs-major-version 27) '(:extend t))
+                     :background
+                     ,(or (face-foreground (transient--key-face nil 
'non-suffix)
+                                           nil t)
+                          "#gray60"))))
+    (concat (propertize "__" 'face face 'display `(space :height (,height)))
+            (propertize "\n" 'face face 'line-height t))))
+
+(defmacro transient-with-shadowed-buffer (&rest body)
+  "While in the transient buffer, temporarily make the shadowed buffer 
current."
+  (declare (indent 0) (debug t))
+  `(with-current-buffer (or transient--shadowed-buffer (current-buffer))
+     ,@body))
+
 (defun transient--insert-groups ()
   (let ((groups (cl-mapcan (lambda (group)
                              (let ((hide (oref group hide)))
                                (and (not (and (functionp hide)
-                                              (funcall   hide)))
+                                              (transient-with-shadowed-buffer
+                                                (funcall hide))))
                                     (list group))))
                            transient--layout))
         group)
@@ -3324,23 +3592,25 @@ have a history of their own.")
 
 (cl-defmethod transient--insert-group :around ((group transient-group))
   "Insert GROUP's description, if any."
-  (when-let ((desc (transient-format-description group)))
+  (when-let ((desc (transient-with-shadowed-buffer
+                     (transient-format-description group))))
     (insert desc ?\n))
   (let ((transient--max-group-level
-         (max (oref group level) transient--max-group-level)))
+         (max (oref group level) transient--max-group-level))
+        (transient--pending-group group))
     (cl-call-next-method group)))
 
 (cl-defmethod transient--insert-group ((group transient-row))
   (transient--maybe-pad-keys group)
   (dolist (suffix (oref group suffixes))
-    (insert (transient-format suffix))
+    (insert (transient-with-shadowed-buffer (transient-format suffix)))
     (insert "   "))
   (insert ?\n))
 
 (cl-defmethod transient--insert-group ((group transient-column))
   (transient--maybe-pad-keys group)
   (dolist (suffix (oref group suffixes))
-    (let ((str (transient-format suffix)))
+    (let ((str (transient-with-shadowed-buffer (transient-format suffix))))
       (insert str)
       (unless (string-match-p ".\n\\'" str)
         (insert ?\n)))))
@@ -3350,10 +3620,11 @@ have a history of their own.")
           (mapcar
            (lambda (column)
              (transient--maybe-pad-keys column group)
-             (let ((rows (mapcar #'transient-format (oref column suffixes))))
-               (when-let ((desc (transient-format-description column)))
-                 (push desc rows))
-               (flatten-tree rows)))
+             (transient-with-shadowed-buffer
+               (let ((rows (mapcar #'transient-format (oref column suffixes))))
+                 (when-let ((desc (transient-format-description column)))
+                   (push desc rows))
+                 (flatten-tree rows))))
            (oref group suffixes)))
          (vp (or (oref transient--prefix variable-pitch)
                  transient-align-variable-pitch))
@@ -3393,15 +3664,6 @@ have a history of their own.")
             (when (= c (1- cs))
               (insert ?\n))))))))
 
-(defun transient--pixel-width (string)
-  (save-window-excursion
-    (with-temp-buffer
-      (insert string)
-      (set-window-dedicated-p nil nil)
-      (set-window-buffer nil (current-buffer))
-      (car (window-text-pixel-size
-            nil (line-beginning-position) (point))))))
-
 (cl-defmethod transient--insert-group ((group transient-subgroups))
   (let* ((subgroups (oref group suffixes))
          (n (length subgroups)))
@@ -3432,36 +3694,31 @@ making `transient--original-buffer' current.")
   "Return a string containing just the ARG character."
   (char-to-string arg))
 
-(cl-defmethod transient-format :around ((obj transient-infix))
-  "When reading user input for this infix, then highlight it."
+(cl-defmethod transient-format :around ((obj transient-suffix))
+  "Add additional formatting if appropriate.
+When reading user input for this infix, then highlight it.
+When edit-mode is enabled, then prepend the level information.
+When `transient-enable-popup-navigation' is non-nil then format
+as a button."
   (let ((str (cl-call-next-method obj)))
-    (when (eq obj transient--active-infix)
-      (setq str (concat str "\n"))
-      (add-face-text-property
-       (if (eq this-command 'transient-set-level) 3 0)
-       (length str)
-       'transient-active-infix nil str))
+    (when (and (cl-typep obj 'transient-infix)
+               (eq (oref obj command) this-original-command)
+               (active-minibuffer-window))
+      (setq str (transient--add-face str 'transient-active-infix)))
+    (when transient--editp
+      (setq str (concat (let ((level (oref obj level)))
+                          (propertize (format " %s " level)
+                                      'face (if (transient--use-level-p level 
t)
+                                                'transient-enabled-suffix
+                                              'transient-disabled-suffix)))
+                        str)))
+    (when (and transient-enable-popup-navigation
+               (slot-boundp obj 'command))
+      (setq str (make-text-button str nil
+                                  'type 'transient
+                                  'command (oref obj command))))
     str))
 
-(cl-defmethod transient-format :around ((obj transient-suffix))
-  "When edit-mode is enabled, then prepend the level information.
-Optional support for popup buttons is also implemented here."
-  (let ((str (concat
-              (and transient--editp
-                   (let ((level (oref obj level)))
-                     (propertize (format " %s " level)
-                                 'face (if (transient--use-level-p level t)
-                                           'transient-enabled-suffix
-                                         'transient-disabled-suffix))))
-              (cl-call-next-method obj))))
-    (when (oref obj inapt)
-      (add-face-text-property 0 (length str) 'transient-inapt-suffix nil str))
-    (if transient-enable-popup-navigation
-        (make-text-button str nil
-                          'type 'transient
-                          'command (oref obj command))
-      str)))
-
 (cl-defmethod transient-format ((obj transient-infix))
   "Return a string generated using OBJ's `format'.
 %k is formatted using `transient-format-key'.
@@ -3483,10 +3740,19 @@ Optional support for popup buttons is also implemented 
here."
 (cl-defgeneric transient-format-key (obj)
   "Format OBJ's `key' for display and return the result.")
 
+(cl-defmethod transient-format-key :around ((obj transient-suffix))
+  "Add `transient-inapt-suffix' face if suffix is inapt."
+  (let ((str (cl-call-next-method)))
+    (if (oref obj inapt)
+        (transient--add-face str 'transient-inapt-suffix)
+      str)))
+
 (cl-defmethod transient-format-key ((obj transient-suffix))
   "Format OBJ's `key' for display and return the result."
-  (let ((key (oref obj key))
-        (cmd (oref obj command)))
+  (let ((key (if (slot-boundp obj 'key) (oref obj key) ""))
+        (cmd (and (slot-boundp obj 'command) (oref obj command))))
+    (when-let ((width (oref transient--pending-group pad-keys)))
+      (setq key (truncate-string-to-width key width nil ?\s)))
     (if transient--redisplay-key
         (let ((len (length transient--redisplay-key))
               (seq (cl-coerce (edmacro-parse-keys key t) 'list)))
@@ -3503,7 +3769,7 @@ Optional support for popup buttons is also implemented 
here."
               (setq pre (string-replace "TAB" "C-i" pre))
               (setq suf (string-replace "RET" "C-m" suf))
               (setq suf (string-replace "TAB" "C-i" suf))
-              ;; We use e.g. "-k" instead of the more correct "- k",
+              ;; We use e.g., "-k" instead of the more correct "- k",
               ;; because the former is prettier.  If we did that in
               ;; the definition, then we want to drop the space that
               ;; is reinserted above.  False-positives are possible
@@ -3513,33 +3779,27 @@ Optional support for popup buttons is also implemented 
here."
                 (setq suf (string-replace " " "" suf)))
               (concat (propertize pre 'face 'transient-unreachable-key)
                       (and (string-prefix-p (concat pre " ") key) " ")
-                      (transient--colorize-key suf cmd)
+                      (propertize suf 'face (transient--key-face cmd))
                       (save-excursion
                         (and (string-match " +\\'" key)
                              (propertize (match-string 0 key)
                                          'face 'fixed-pitch))))))
            ((transient--lookup-key transient-sticky-map (kbd key))
-            (transient--colorize-key key cmd))
+            (propertize key 'face (transient--key-face cmd)))
            (t
             (propertize key 'face 'transient-unreachable-key))))
-      (transient--colorize-key key cmd))))
-
-(defun transient--colorize-key (key command)
-  (propertize key 'face
-              (or (and (transient--semantic-coloring-p)
-                       (transient--suffix-color command))
-                  'transient-key)))
+      (propertize key 'face (transient--key-face cmd)))))
 
 (cl-defmethod transient-format-key :around ((obj transient-argument))
+  "Handle `transient-highlight-mismatched-keys'."
   (let ((key (cl-call-next-method obj)))
-    (cond ((not transient-highlight-mismatched-keys))
-          ((not (slot-boundp obj 'shortarg))
-           (add-face-text-property
-            0 (length key) 'transient-nonstandard-key nil key))
-          ((not (string-equal key (oref obj shortarg)))
-           (add-face-text-property
-            0 (length key) 'transient-mismatched-key nil key)))
-    key))
+    (cond
+     ((not transient-highlight-mismatched-keys) key)
+     ((not (slot-boundp obj 'shortarg))
+      (transient--add-face key 'transient-nonstandard-key))
+     ((not (string-equal key (oref obj shortarg)))
+      (transient--add-face key 'transient-mismatched-key))
+     (key))))
 
 (cl-defgeneric transient-format-description (obj)
   "Format OBJ's `description' for display and return the result.")
@@ -3548,10 +3808,14 @@ Optional support for popup buttons is also implemented 
here."
   "The `description' slot may be a function, in which case that is
 called inside the correct buffer (see `transient--insert-group')
 and its value is returned to the caller."
-  (and-let* ((desc (oref obj description)))
-    (if (functionp desc)
-        (with-current-buffer transient--original-buffer
-          (funcall desc))
+  (and-let* ((desc (oref obj description))
+             (desc (if (functionp desc)
+                       (if (= (car (func-arity desc)) 1)
+                           (funcall desc obj)
+                         (funcall desc))
+                     desc)))
+    (if-let* ((face (transient--get-face obj 'face)))
+        (transient--add-face desc face t)
       desc)))
 
 (cl-defmethod transient-format-description ((obj transient-group))
@@ -3573,16 +3837,19 @@ If the OBJ's `key' is currently unreachable, then apply 
the face
                        (funcall (oref transient--prefix suffix-description)
                                 obj))
                   (propertize "(BUG: no description)" 'face 'error))))
-    (cond ((transient--key-unreachable-p obj)
-           (propertize desc 'face 'transient-unreachable))
-          ((and transient-highlight-higher-levels
-                (> (max (oref obj level) transient--max-group-level)
-                   transient--default-prefix-level))
-           (add-face-text-property
-            0 (length desc) 'transient-higher-level nil desc)
-           desc)
-          (t
-           desc))))
+    (when (if transient--all-levels-p
+              (> (oref obj level) transient--default-prefix-level)
+            (and transient-highlight-higher-levels
+                 (> (max (oref obj level) transient--max-group-level)
+                    transient--default-prefix-level)))
+      (setq desc (transient--add-face desc 'transient-higher-level)))
+    (when-let ((inapt-face (and (oref obj inapt)
+                                (transient--get-face obj 'inapt-face))))
+      (setq desc (transient--add-face desc inapt-face)))
+    (when (and (slot-boundp obj 'key)
+               (transient--key-unreachable-p obj))
+      (setq desc (transient--add-face desc 'transient-unreachable)))
+    desc))
 
 (cl-defgeneric transient-format-value (obj)
   "Format OBJ's value for display and return the result.")
@@ -3596,24 +3863,32 @@ If the OBJ's `key' is currently unreachable, then apply 
the face
 (cl-defmethod transient-format-value ((obj transient-option))
   (let ((argument (oref obj argument)))
     (if-let ((value (oref obj value)))
-        (propertize
-         (cl-ecase (oref obj multi-value)
-           ((nil)    (concat argument value))
-           ((t rest) (concat argument
-                             (and (not (string-suffix-p " " argument)) " ")
-                             (mapconcat #'prin1-to-string value " ")))
-           (repeat   (mapconcat (lambda (v) (concat argument v)) value " ")))
-         'face 'transient-value)
-      (propertize argument 'face 'transient-inactive-value))))
+        (pcase-exhaustive (oref obj multi-value)
+          ('nil
+           (concat (propertize argument 'face 'transient-argument)
+                   (propertize value    'face 'transient-value)))
+          ((or 't 'rest)
+           (concat (propertize (if (string-suffix-p " " argument)
+                                   argument
+                                 (concat argument " "))
+                               'face 'transient-argument)
+                   (propertize (mapconcat #'prin1-to-string value " ")
+                               'face 'transient-value)))
+          ('repeat
+           (mapconcat (lambda (value)
+                        (concat (propertize argument 'face 'transient-argument)
+                                (propertize value    'face 'transient-value)))
+                      value " ")))
+      (propertize argument 'face 'transient-inactive-argument))))
 
 (cl-defmethod transient-format-value ((obj transient-switches))
   (with-slots (value argument-format choices) obj
     (format (propertize argument-format
                         'face (if value
-                                  'transient-value
-                                'transient-inactive-value))
-            (concat
-             (propertize "[" 'face 'transient-inactive-value)
+                                  'transient-argument
+                                'transient-inactive-argument))
+            (format
+             (propertize "[%s]" 'face 'transient-delimiter)
              (mapconcat
               (lambda (choice)
                 (propertize choice 'face
@@ -3621,8 +3896,30 @@ If the OBJ's `key' is currently unreachable, then apply 
the face
                                 'transient-value
                               'transient-inactive-value)))
               choices
-              (propertize "|" 'face 'transient-inactive-value))
-             (propertize "]" 'face 'transient-inactive-value)))))
+              (propertize "|" 'face 'transient-delimiter))))))
+
+(defun transient--add-face (string face &optional append beg end)
+  (let ((str (copy-sequence string)))
+    (add-face-text-property (or beg 0) (or end (length str)) face append str)
+    str))
+
+(defun transient--get-face (obj slot)
+  (and-let* ((! (slot-exists-p obj slot))
+             (! (slot-boundp   obj slot))
+             (face (slot-value obj slot)))
+    (if (and (not (facep face))
+             (functionp face))
+        (funcall face)
+      face)))
+
+(defun transient--key-face (&optional cmd enforce-type)
+  (or (and transient-semantic-coloring
+           (not transient--helpp)
+           (not transient--editp)
+           (or (and cmd (get cmd 'transient-face))
+               (get (transient--get-pre-command cmd enforce-type)
+                    'transient-face)))
+      (if cmd 'transient-key 'transient-key-noop)))
 
 (defun transient--key-unreachable-p (obj)
   (and transient--redisplay-key
@@ -3637,19 +3934,24 @@ If the OBJ's `key' is currently unreachable, then apply 
the face
     (and val (not (integerp val)) val)))
 
 (defun transient--maybe-pad-keys (group &optional parent)
-  (when-let ((pad (if (slot-boundp group 'pad-keys)
-                      (oref group pad-keys)
-                    (and parent
-                         (slot-boundp parent 'pad-keys)
-                         (oref parent pad-keys)))))
-    (let ((width (apply #'max
-                        (cons (if (integerp pad) pad 0)
-                              (mapcar (lambda (suffix)
-                                        (length (oref suffix key)))
-                                      (oref group suffixes))))))
-      (dolist (suffix (oref group suffixes))
-        (oset suffix key
-              (truncate-string-to-width (oref suffix key) width nil ?\s))))))
+  (when-let ((pad (or (oref group pad-keys)
+                      (and parent (oref parent pad-keys)))))
+    (oset group pad-keys
+          (apply #'max (cons (if (integerp pad) pad 0)
+                             (seq-keep (lambda (suffix)
+                                         (and (eieio-object-p suffix)
+                                              (slot-boundp suffix 'key)
+                                              (length (oref suffix key))))
+                                       (oref group suffixes)))))))
+
+(defun transient--pixel-width (string)
+  (save-window-excursion
+    (with-temp-buffer
+      (insert string)
+      (set-window-dedicated-p nil nil)
+      (set-window-buffer nil (current-buffer))
+      (car (window-text-pixel-size
+            nil (line-beginning-position) (point))))))
 
 (defun transient-command-summary-or-name (obj)
   "Return the summary or name of the command represented by OBJ.
@@ -3677,7 +3979,7 @@ if non-nil, else show the `man-page' if non-nil, else use
     (cond (show-help (funcall show-help obj))
           (info-manual (transient--show-manual info-manual))
           (man-page (transient--show-manpage man-page))
-          (t (transient--describe-function command)))))
+          ((transient--describe-function command)))))
 
 (cl-defmethod transient-show-help ((obj transient-suffix))
   "Call `show-help' if non-nil, else use `describe-function'.
@@ -3691,9 +3993,9 @@ prefix method."
                        'transient--prefix)))
       (and prefix (not (eq (oref transient--prefix command) this-command))
            (prog1 t (transient-show-help prefix)))))
-   (t (if-let ((show-help (oref obj show-help)))
-          (funcall show-help obj)
-        (transient--describe-function this-command)))))
+   ((if-let ((show-help (oref obj show-help)))
+        (funcall show-help obj)
+      (transient--describe-function this-command)))))
 
 (cl-defmethod transient-show-help ((obj transient-infix))
   "Call `show-help' if non-nil, else show the `man-page'
@@ -3713,7 +4015,7 @@ manpage, then try to jump to the correct location."
   (transient--describe-function cmd))
 
 (defun transient--describe-function (fn)
-  (describe-function (if (symbolp fn) fn 'transient--anonymous-infix-argument))
+  (describe-function fn)
   (unless (derived-mode-p 'help-mode)
     (when-let* ((buf (get-buffer "*Help*"))
                 (win (or (and buf (get-buffer-window buf))
@@ -3723,21 +4025,6 @@ manpage, then try to jump to the correct location."
                                      (window-list)))))
       (select-window win))))
 
-(defun transient--anonymous-infix-argument ()
-  "Cannot show any documentation for this anonymous infix command.
-
-The infix command in question was defined anonymously, i.e.,
-it was define when the prefix command that it belongs to was
-defined, which means that it gets no docstring and also that
-no symbol is bound to it.
-
-When you request help for an infix command, then we usually
-show the respective man-page and jump to the location where
-the respective argument is being described.
-
-Because the containing prefix command does not specify any
-man-page, we cannot do that in this case.  Sorry about that.")
-
 (defun transient--show-manual (manual)
   (info manual))
 
@@ -3830,37 +4117,23 @@ Suffixes on levels %s and %s are unavailable.\n"
                (propertize (format ">=%s" (1+ level))
                            'face 'transient-disabled-suffix))))))
 
-(defvar-keymap transient-resume-mode-map
-  :doc "Keymap for `transient-resume-mode'.
-
-This keymap remaps every command that would usually just quit the
-documentation buffer to `transient-resume', which additionally
-resumes the suspended transient."
-  "<remap> <Man-quit>"    #'transient-resume
-  "<remap> <Info-exit>"   #'transient-resume
-  "<remap> <quit-window>" #'transient-resume)
-
-(define-minor-mode transient-resume-mode
-  "Auxiliary minor-mode used to resume a transient after viewing help.")
-
-(defun transient-toggle-debug ()
-  "Toggle debugging statements for transient commands."
-  (interactive)
-  (setq transient--debug (not transient--debug))
-  (message "Debugging transient %s"
-           (if transient--debug "enabled" "disabled")))
-
 ;;; Popup Navigation
 
-(defun transient-popup-navigation-help ()
-  "Inform the user how to enable popup navigation commands."
-  (interactive)
-  (message "This command is only available if `%s' is non-nil"
-           'transient-enable-popup-navigation))
+(defun transient-scroll-up (&optional arg)
+  "Scroll text of transient popup window upward ARG lines.
+If ARG is nil scroll near full screen.  This is a wrapper
+around `scroll-up-command' (which see)."
+  (interactive "^P")
+  (with-selected-window transient--window
+    (scroll-up-command arg)))
 
-(define-button-type 'transient
-  'face nil
-  'keymap transient-button-map)
+(defun transient-scroll-down (&optional arg)
+  "Scroll text of transient popup window down ARG lines.
+If ARG is nil scroll near full screen.  This is a wrapper
+around `scroll-down-command' (which see)."
+  (interactive "^P")
+  (with-selected-window transient--window
+    (scroll-down-command arg)))
 
 (defun transient-backward-button (n)
   "Move to the previous button in the transient popup buffer.
@@ -3876,6 +4149,10 @@ See `forward-button' for information about N."
   (with-selected-window transient--window
     (forward-button n t)))
 
+(define-button-type 'transient
+  'face nil
+  'keymap transient-button-map)
+
 (defun transient--goto-button (command)
   (cond
    ((stringp command)
@@ -3953,36 +4230,6 @@ search instead."
   (select-window transient--original-window)
   (transient--resume-override))
 
-;;;; Hydra Color Emulation
-
-(defun transient--semantic-coloring-p ()
-  (and transient-semantic-coloring
-       (not transient--helpp)
-       (not transient--editp)))
-
-(defun transient--suffix-color (command)
-  (or (get command 'transient-color)
-      (get (transient--get-predicate-for command) 'transient-color)))
-
-(defun transient--prefix-color (command)
-  (let* ((nonsuf (or (oref command transient-non-suffix)
-                     'transient--do-warn))
-         (nonsuf (if (memq nonsuf '(transient--do-noop transient--do-warn))
-                     'disallow
-                   (get nonsuf 'transient-color)))
-         (suffix (if-let ((pred (oref command transient-suffix)))
-                     (get pred 'transient-color)
-                   (if (eq nonsuf 'transient-red)
-                       'transient-red
-                     'transient-blue))))
-    (pcase (list suffix nonsuf)
-      (`(transient-purple ,_)           'transient-purple)
-      ('(transient-red  disallow)       'transient-amaranth)
-      ('(transient-blue disallow)       'transient-teal)
-      ('(transient-red  transient-red)  'transient-pink)
-      ('(transient-red  transient-blue) 'transient-red)
-      ('(transient-blue transient-blue) 'transient-blue))))
-
 ;;;; Edebug
 
 (defun transient--edebug-command-p ()
@@ -4044,7 +4291,7 @@ we stop there."
   (let ((key (oref obj key)))
     (cond ((string-equal key "q") "Q")
           ((string-equal key "Q") "M-q")
-          (t key))))
+          (key))))
 
 (defun transient--force-fixed-pitch ()
   (require 'face-remap)
@@ -4079,8 +4326,7 @@ we stop there."
                 (regexp-opt (list "transient-define-prefix"
                                   "transient-define-infix"
                                   "transient-define-argument"
-                                  "transient-define-suffix"
-                                  "transient-define-groups")
+                                  "transient-define-suffix")
                             t)
                 "\\_>[ \t'(]*"
                 "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
diff --git a/lisp/treesit.el b/lisp/treesit.el
index da8226f7d8a..c6b9d8ff4bc 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -385,6 +385,7 @@ If NAMED is non-nil, collect named child only."
   "Return the index of NODE in its parent.
 If NAMED is non-nil, count named child only."
   (let ((count 0))
+    ;; TODO: Use next-sibling as it's more efficient.
     (while (setq node (treesit-node-prev-sibling node named))
       (cl-incf count))
     count))
@@ -392,7 +393,7 @@ If NAMED is non-nil, count named child only."
 (defun treesit-node-field-name (node)
   "Return the field name of NODE as a child of its parent."
   (when-let ((parent (treesit-node-parent node))
-             (idx (treesit-node-index node)))
+             (idx (treesit-node-index node t)))
     (treesit-node-field-name-for-child parent idx)))
 
 (defun treesit-node-get (node instructions)
@@ -690,7 +691,7 @@ property.  If LANGUAGE is non-nil, only return parsers for 
LANGUAGE."
 
 (defun treesit--update-ranges-local
     (query embedded-lang &optional beg end)
-  "Update range for local parsers betwwen BEG and END.
+  "Update range for local parsers between BEG and END.
 Use QUERY to get the ranges, and make sure each range has a local
 parser for EMBEDDED-LANG."
   ;; Clean up.
@@ -2358,7 +2359,7 @@ the current line if the beginning of the defun is 
indented."
          (forward-line 1))
         ;; Moving backward, but there are some whitespace (and only
         ;; whitespace) between point and BOL: go back to BOL.
-        ((looking-back (rx (+ (or " " "\t")))
+        ((looking-back (rx bol (+ (or " " "\t")))
                        (line-beginning-position))
          (beginning-of-line))))
 
diff --git a/lisp/url/url-http.el b/lisp/url/url-http.el
index ada6341ee73..947c6517ed1 100644
--- a/lisp/url/url-http.el
+++ b/lisp/url/url-http.el
@@ -358,10 +358,6 @@ Use `url-http-referer' as the Referer-header (subject to 
`url-privacy-level')."
                   (url-port url-http-target-url))
                (format "Host: %s\r\n"
                        (url-http--encode-string (puny-encode-domain host))))
-             ;; Who its from
-             (if url-personal-mail-address
-                 (concat
-                  "From: " url-personal-mail-address "\r\n"))
              ;; Encodings we understand
              (if (or url-mime-encoding-string
                     ;; MS-Windows loads zlib dynamically, so recheck
diff --git a/lisp/url/url-privacy.el b/lisp/url/url-privacy.el
index 2be77b33035..be4b063d18f 100644
--- a/lisp/url/url-privacy.el
+++ b/lisp/url/url-privacy.el
@@ -59,16 +59,6 @@
            ('tty "TTY")
            (_ nil)))))
 
-  (setq url-personal-mail-address (or url-personal-mail-address
-                                     user-mail-address
-                                     (format "%s@%s"  (user-real-login-name)
-                                             (system-name))))
-
-  (if (or (memq url-privacy-level '(paranoid high))
-         (and (listp url-privacy-level)
-              (memq 'email url-privacy-level)))
-      (setq url-personal-mail-address nil))
-
   (setq url-os-type
        (cond
         ((or (eq url-privacy-level 'paranoid)
diff --git a/lisp/url/url-vars.el b/lisp/url/url-vars.el
index 630de7f4e43..6d7d0d3c94c 100644
--- a/lisp/url/url-vars.el
+++ b/lisp/url/url-vars.el
@@ -90,6 +90,7 @@ This is what is sent to HTTP servers as the FROM field in an 
HTTP
 request."
   :type '(choice (const :tag "Unspecified" nil) string)
   :group 'url)
+(make-obsolete-variable 'url-personal-mail-address nil "30.1")
 
 (defcustom url-directory-index-file "index.html"
   "The filename to look for when indexing a directory.
@@ -113,18 +114,22 @@ paranoid -- don't send anything
 
 If a list, this should be a list of symbols of what NOT to send.
 Valid symbols are:
-email    -- the email address
+email    -- the email address (in Emacs 29 or older)
 os       -- the operating system info
 emacs    -- the version of Emacs
 lastloc  -- the last location (see also `url-lastloc-privacy-level')
 agent    -- do not send the User-Agent string
 cookies  -- never accept HTTP cookies
 
+Emacs 30 and newer never includes the email address in the
+User-Agent string.  If you expect to use older versions of Emacs,
+it is recommended to always customize this list to include `email'.
+
 Samples:
 
  (setq url-privacy-level \\='high)
  (setq url-privacy-level \\='(email lastloc))    ;; equivalent to \\='high
- (setq url-privacy-level \\='(os))
+ (setq url-privacy-level \\='(email lastloc os emacs))
 
 ::NOTE::
 This variable controls several other variables and is _NOT_ automatically
diff --git a/lisp/use-package/use-package-core.el 
b/lisp/use-package/use-package-core.el
index 34c45b7aec3..2897b60b2f9 100644
--- a/lisp/use-package/use-package-core.el
+++ b/lisp/use-package/use-package-core.el
@@ -1619,7 +1619,7 @@ ARG is the normalized input to the `:vc' keyword, as 
returned by
 the `use-package-normalize/:vc' function.
 
 REST is a plist of other (following) keywords and their
-arguments, each having already been normalised by the respective
+arguments, each having already been normalized by the respective
 function.
 
 STATE is a plist of any state that keywords processed before
@@ -1690,7 +1690,7 @@ node `(use-package) Creating an extension'."
       (`(,(pred symbolp) . ,(or (pred plistp)    ; plist/version string + name
                                 (pred stringp)))
        (use-package-normalize--vc-arg arg))
-      (_ (use-package-error "Unrecognised argument to :vc.\
+      (_ (use-package-error "Unrecognized argument to :vc.\
  The keyword wants an argument of nil, t, a name of a package,\
  or a cons-cell as accepted by `package-vc-selected-packages', where \
  the accepted plist is augmented by a `:rev' keyword.")))))
diff --git a/lisp/vc/log-edit.el b/lisp/vc/log-edit.el
index c77f4494c1a..39e0799ba73 100644
--- a/lisp/vc/log-edit.el
+++ b/lisp/vc/log-edit.el
@@ -61,12 +61,12 @@
   "C-c C-d" #'log-edit-show-diff
   "C-c C-f" #'log-edit-show-files
   "C-c C-k" #'log-edit-kill-buffer
-  "C-a"     #'log-edit-beginning-of-line
   "M-n"     #'log-edit-next-comment
   "M-p"     #'log-edit-previous-comment
   "M-r"     #'log-edit-comment-search-backward
   "M-s"     #'log-edit-comment-search-forward
-  "C-c ?"   #'log-edit-mode-help)
+  "C-c ?"   #'log-edit-mode-help
+  "<remap> <move-beginning-of-line>" #'log-edit-beginning-of-line)
 
 (easy-menu-define log-edit-menu log-edit-mode-map
   "Menu used for `log-edit-mode'."
diff --git a/lisp/vc/log-view.el b/lisp/vc/log-view.el
index af24fcfd398..6c3abd15d8d 100644
--- a/lisp/vc/log-view.el
+++ b/lisp/vc/log-view.el
@@ -516,7 +516,8 @@ If called interactively, visit the version at point."
     (switch-to-buffer (vc-find-revision (if log-view-per-file-logs
                                            (log-view-current-file)
                                          (car log-view-vc-fileset))
-                                       (log-view-current-tag)))))
+                                       (log-view-current-tag)
+                                        log-view-vc-backend))))
 
 
 (defun log-view-extract-comment ()
@@ -562,7 +563,8 @@ If called interactively, annotate the version at point."
     (vc-annotate (if log-view-per-file-logs
                     (log-view-current-file)
                   (car log-view-vc-fileset))
-                (log-view-current-tag))))
+                (log-view-current-tag)
+                 nil nil nil log-view-vc-backend)))
 
 ;;
 ;; diff
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 2e057ecfaa7..24469f04f7c 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -89,6 +89,7 @@
 ;; - make-version-backups-p (file)                 NOT NEEDED
 ;; - previous-revision (file rev)                  OK
 ;; - next-revision (file rev)                      OK
+;; - file-name-changes (rev)                       OK
 ;; - check-headers ()                              COULD BE SUPPORTED
 ;; - delete-file (file)                            OK
 ;; - rename-file (old new)                         OK
@@ -152,6 +153,18 @@ comparing changes.  See Man page `git-blame' for more."
                  (repeat :tag "Argument List" :value ("") string))
   :version "30.1")
 
+(defcustom vc-git-file-name-changes-switches '("-M" "-C")
+  "String or list of string to pass to Git when finding previous names.
+
+This option should usually at least contain '-M'.  You can adjust
+the flags to change the similarity thresholds (default 50%).  Or
+add `--find-copies-harder' (slower in large projects, since it
+uses a full scan)."
+  :type '(choice (const :tag "None" nil)
+                 (string :tag "Argument String")
+                 (repeat :tag "Argument List" :value ("") string))
+  :version "30.1")
+
 (defcustom vc-git-resolve-conflicts t
   "When non-nil, mark conflicted file as resolved upon saving.
 That is performed after all conflict markers in it have been
@@ -1416,7 +1429,16 @@ This prompts for a branch to merge from."
 ;; Long explanation here:
 ;; 
https://stackoverflow.com/questions/46487476/git-log-follow-graph-skips-commits
 (defcustom vc-git-print-log-follow nil
-  "If true, follow renames in Git logs for a single file."
+  "If non-nil, use the flag `--follow' when producing single file logs.
+
+A non-nil value will make the printed log automatically follow
+the file renames.  The downsides is that the log produced this
+way may omit certain (merge) commits, and that `log-view-diff'
+fails on commits that used the previous name, in that log buffer.
+
+When this variable is nil, and the log ends with a rename, we
+show a button below that which allows to show the log for the
+file name before the rename."
   :type 'boolean
   :version "26.1")
 
@@ -1866,6 +1888,31 @@ This requires git 1.8.4 or later, for the \"-L\" option 
of \"git log\"."
                    (progn (forward-line 1) (1- (point)))))))))
     (or (vc-git-symbolic-commit next-rev) next-rev)))
 
+(defun vc-git-file-name-changes (rev)
+  (with-temp-buffer
+    (let ((root (vc-git-root default-directory)))
+      (unless vc-git-print-log-follow
+        (apply #'vc-git-command (current-buffer) t nil
+               "diff"
+               "--name-status"
+               "--diff-filter=ADCR"
+               (concat rev "^") rev
+               (vc-switches 'git 'file-name-changes)))
+      (let (res)
+        (goto-char (point-min))
+        (while (re-search-forward 
"^\\([ADCR]\\)[0-9]*\t\\([^\n\t]+\\)\\(?:\t\\([^\n\t]+\\)\\)?" nil t)
+          (pcase (match-string 1)
+            ("A" (push (cons nil (match-string 2)) res))
+            ("D" (push (cons (match-string 2) nil) res))
+            ((or "C" "R") (push (cons (match-string 2) (match-string 3)) res))
+            ;; ("M" (push (cons (match-string 1) (match-string 1)) res))
+            ))
+        (mapc (lambda (c)
+                (if (car c) (setcar c (expand-file-name (car c) root)))
+                (if (cdr c) (setcdr c (expand-file-name (cdr c) root))))
+              res)
+        (nreverse res)))))
+
 (defun vc-git-delete-file (file)
   (vc-git-command nil 0 file "rm" "-f" "--"))
 
diff --git a/lisp/vc/vc-hg.el b/lisp/vc/vc-hg.el
index 9df517ea847..d6dadb74469 100644
--- a/lisp/vc/vc-hg.el
+++ b/lisp/vc/vc-hg.el
@@ -77,6 +77,7 @@
 ;; - make-version-backups-p (file)             ??
 ;; - previous-revision (file rev)              OK
 ;; - next-revision (file rev)                  OK
+;; - file-name-changes (rev)                   OK
 ;; - check-headers ()                          ??
 ;; - delete-file (file)                        TEST IT
 ;; - rename-file (old new)                     OK
@@ -1203,6 +1204,22 @@ REV is ignored."
         (vc-hg-command buffer 0 file "cat" "-r" rev)
       (vc-hg-command buffer 0 file "cat"))))
 
+(defun vc-hg-file-name-changes (rev)
+  (unless (member "--follow" vc-hg-log-switches)
+    (with-temp-buffer
+      (let ((root (vc-hg-root default-directory)))
+        (vc-hg-command (current-buffer) t nil
+                       "log" "-g" "-p" "-r" rev)
+        (let (res)
+          (goto-char (point-min))
+          (while (re-search-forward "^diff --git a/\\([^ \n]+\\) b/\\([^ 
\n]+\\)" nil t)
+            (when (not (equal (match-string 1) (match-string 2)))
+              (push (cons
+                     (expand-file-name (match-string 1) root)
+                     (expand-file-name (match-string 2) root))
+                    res)))
+          (nreverse res))))))
+
 (defun vc-hg-find-ignore-file (file)
   "Return the root directory of the repository of FILE."
   (expand-file-name ".hgignore"
diff --git a/lisp/vc/vc-rcs.el b/lisp/vc/vc-rcs.el
index 3d6907cbec1..04c1946358d 100644
--- a/lisp/vc/vc-rcs.el
+++ b/lisp/vc/vc-rcs.el
@@ -714,7 +714,7 @@ Optional arg REVISION is a revision to annotate from."
             (insert insn)
           (delete-char insn)))
       ;; Now apply the forward-chronological edits (directly from the
-      ;; parse-tree) for the branch(es), if necessary.  We re-use vars
+      ;; parse-tree) for the branch(es), if necessary.  We reuse vars
       ;; `pre' and `meta' for the sake of internal func `r/d/a'.
       (while nbls
         (setq pre (cdr (pop nbls)))
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 3085e4b9f76..4e6581f7f27 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -517,6 +517,13 @@
 ;;   Return the revision number that precedes REV for FILE, or nil if no such
 ;;   revision exists.
 ;;
+;; - file-name-changes (rev)
+;;
+;;   Return the list of pairs with changes in file names in REV.  When
+;;   a file was added, it should be a cons with nil car.  When
+;;   deleted, a cons with nil cdr.  When copied or renamed, a cons
+;;   with the source name as car and destination name as cdr.
+;;
 ;; - next-revision (file rev)
 ;;
 ;;   Return the revision number that follows REV for FILE, or nil if no such
@@ -668,7 +675,7 @@
 ;;;; New Primitives:
 ;;
 ;; - uncommit: undo last checkin, leave changes in place in the workfile,
-;;   stash the commit comment for re-use.
+;;   stash the commit comment for reuse.
 ;;
 ;; - deal with push operations.
 ;;
@@ -2686,18 +2693,70 @@ Not all VC backends support short logs!")
 (defun vc-print-log-setup-buttons (working-revision is-start-revision limit 
pl-return)
   "Insert at the end of the current buffer buttons to show more log entries.
 In the new log, leave point at WORKING-REVISION (if non-nil).
-LIMIT is the number of entries currently shown.
-Does nothing if IS-START-REVISION is non-nil, or if LIMIT is nil,
-or if PL-RETURN is `limit-unsupported'."
+LIMIT is the current maximum number of entries shown.  Does
+nothing if IS-START-REVISION is non-nil and LIMIT is 1, or if
+LIMIT is nil, or if PL-RETURN is `limit-unsupported'."
+  ;; LIMIT=1 is set by vc-annotate-show-log-revision-at-line
+  ;; or by vc-print-root-log with current-prefix-arg=1.
+  ;; In either case only one revision is wanted, no buttons.
   (when (and limit (not (eq 'limit-unsupported pl-return))
-            (not is-start-revision))
+             (not (and is-start-revision
+                       (= limit 1))))
     (let ((entries 0))
       (goto-char (point-min))
       (while (re-search-forward log-view-message-re nil t)
         (cl-incf entries))
-      ;; If we got fewer entries than we asked for, then displaying
-      ;; the "more" buttons isn't useful.
-      (when (>= entries limit)
+      (if (< entries limit)
+          ;; The log has been printed in full.  Perhaps it started
+          ;; with a copy or rename?
+          ;; FIXME: We'd probably still want this button even when
+          ;; vc-log-show-limit is customized to 0 (should be rare).
+          (let* ((last-revision (log-view-current-tag (point-max)))
+                 ;; XXX: Could skip this when vc-git-print-log-follow = t.
+                 (name-changes
+                  (condition-case nil
+                      (vc-call-backend log-view-vc-backend
+                                       'file-name-changes last-revision)
+                    (vc-not-supported nil)))
+                 (matching-changes
+                  (cl-delete-if-not (lambda (f) (member f log-view-vc-fileset))
+                                    name-changes :key #'cdr))
+                 (old-names (delq nil (mapcar #'car matching-changes)))
+                 (relatives (mapcar #'file-relative-name old-names)))
+            (when old-names
+              (goto-char (point-max))
+              (unless (looking-back "\n\n" (- (point) 2))
+                (insert "\n"))
+              (insert
+               (format
+                "Renamed from %s"
+                (mapconcat (lambda (s)
+                             (propertize s 'font-lock-face
+                                         'log-view-file))
+                           relatives ", "))
+               " ")
+              ;; TODO: Also print a different button somewhere in the
+              ;; created buffer to be able to go back easily.  Might
+              ;; require some sort of stack/history because a file can
+              ;; be renamed multiple times.
+              (insert-text-button
+               "View log"
+               'action (lambda (&rest _ignore)
+                         (let ((backend log-view-vc-backend))
+                           (with-current-buffer vc-parent-buffer
+                             ;; To set up parent buffer in the new viewer.
+                             (vc-print-log-internal backend old-names
+                                                    last-revision t limit))))
+               ;; XXX: Showing the full history for OLD-NAMES (with
+               ;; IS-START-REVISION=nil) can be better sometimes
+               ;; (e.g. when some edits still occurred after a rename
+               ;; -- multiple branches scenario), but it also can hurt
+               ;; in others because of Git's automatic history
+               ;; simplification: as a result, the logs for some
+               ;; use-package's files before merge could not be found.
+               'help-echo
+               "Show the log for the file name(s) before the rename")))
+        ;; Perhaps there are more entries in the log.
         (goto-char (point-max))
         (insert "\n")
         (insert-text-button
@@ -2725,9 +2784,6 @@ Leave point at WORKING-REVISION, if it is non-nil.
 If IS-START-REVISION is non-nil, start the log from WORKING-REVISION
 \(not all backends support this); i.e., show only WORKING-REVISION and
 earlier revisions.  Show up to LIMIT entries (non-nil means unlimited)."
-  ;; As of 2013/04 the only thing that passes IS-START-REVISION non-nil
-  ;; is vc-annotate-show-log-revision-at-line, which sets LIMIT = 1.
-
   ;; Don't switch to the output buffer before running the command,
   ;; so that any buffer-local settings in the vc-controlled
   ;; buffer can be accessed by the command.
diff --git a/lisp/window.el b/lisp/window.el
index fbdcd611068..40070a4d929 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -6862,6 +6862,7 @@ BUFFER in a window of the selected frame.
 If ARGS is a list whose car is a symbol, use (car ARGS) as a
 function to do the work.  Pass it BUFFER as first argument, and
 pass the elements of (cdr ARGS) as the remaining arguments."
+  (declare (obsolete display-buffer-pop-up-frame "30.1"))
   (if (and args (symbolp (car args)))
       (apply (car args) buffer (cdr args))
     (let ((window (get-buffer-window buffer 0)))
@@ -6881,9 +6882,8 @@ pass the elements of (cdr ARGS) as the remaining 
arguments."
        ;; Stay on the same frame if requested.
        (when (or (cdr (assq 'same-frame args)) (cdr (assq 'same-window args)))
         (let* ((pop-up-windows t)
-               pop-up-frames
                special-display-buffer-names special-display-regexps)
-          (display-buffer buffer)))
+          (display-buffer buffer '((pop-up-frames . nil)))))
        ;; If no window yet, make one in a new frame.
        (let* ((frame
               (with-current-buffer buffer
@@ -6996,6 +6996,13 @@ Emacs Lisp manual for an example."
          (const :tag "Always" t))
   :group 'windows)
 
+(defun window--pop-up-frames (alist)
+ (let* ((override (assq 'pop-up-frames alist))
+        (pop-up (if override (cdr override) pop-up-frames)))
+   (if (eq pop-up 'graphic-only)
+       (display-graphic-p)
+     pop-up)))
+
 (defcustom display-buffer-reuse-frames nil
   "Non-nil means `display-buffer' should reuse frames.
 If the buffer in question is already displayed in a frame, raise
@@ -7742,6 +7749,8 @@ Action alist entries are:
     Possible values are nil (the selected frame), t (any live
     frame), visible (any visible frame), 0 (any visible or
     iconified frame) or an existing live frame.
+ `pop-up-frames' -- Same effect as the eponymous variable.
+    Takes precedence over the variable.
  `pop-up-frame-parameters' -- The value specifies an alist of
     frame parameters to give a new frame, if one is created.
  `window-height' -- The value specifies the desired height of the
@@ -7830,12 +7839,12 @@ specified by the ACTION argument."
                           user-action special-action action extra-action
                           display-buffer-base-action
                           display-buffer-fallback-action))
-           (functions (apply 'append
+           (functions (apply #'append
                              (mapcar (lambda (x)
                                        (setq x (car x))
                                        (if (functionp x) (list x) x))
                                      actions)))
-           (alist (apply 'append (mapcar 'cdr actions)))
+           (alist (apply #'append (mapcar #'cdr actions)))
            window)
       (unless (buffer-live-p buffer)
         (error "Invalid buffer"))
@@ -7978,9 +7987,7 @@ called only by `display-buffer' or a function directly or
 indirectly called by the latter."
   (let* ((alist-entry (assq 'reusable-frames alist))
         (frames (cond (alist-entry (cdr alist-entry))
-                      ((if (eq pop-up-frames 'graphic-only)
-                           (display-graphic-p)
-                         pop-up-frames)
+                      ((window--pop-up-frames alist)
                        0)
                       (display-buffer-reuse-frames 0)
                       (t (last-nonminibuffer-frame))))
@@ -8034,9 +8041,7 @@ indirectly called by the latter."
   (let* ((alist-entry (assq 'reusable-frames alist))
          (alist-mode-entry (assq 'mode alist))
         (frames (cond (alist-entry (cdr alist-entry))
-                      ((if (eq pop-up-frames 'graphic-only)
-                           (display-graphic-p)
-                         pop-up-frames)
+                      ((window--pop-up-frames alist)
                        0)
                       (display-buffer-reuse-frames 0)
                       (t (last-nonminibuffer-frame))))
@@ -8182,9 +8187,7 @@ text-only terminal), try with 
`display-buffer-pop-up-frame'.
 ALIST is an association list of action symbols and values.  See
 Info node `(elisp) Buffer Display Action Alists' for details of
 such alists."
-  (and (if (eq pop-up-frames 'graphic-only)
-          (display-graphic-p)
-        pop-up-frames)
+  (and (window--pop-up-frames alist)
        (display-buffer-pop-up-frame buffer alist)))
 
 (defun display-buffer--maybe-pop-up-window (buffer alist)
@@ -8548,9 +8551,7 @@ indirectly called by the latter."
          (cdr (assq 'inhibit-same-window alist)))
         (frames (cond
                  (alist-entry (cdr alist-entry))
-                 ((if (eq pop-up-frames 'graphic-only)
-                      (display-graphic-p)
-                    pop-up-frames)
+                 ((window--pop-up-frames alist)
                   0)
                  (display-buffer-reuse-frames 0)
                  (t (last-nonminibuffer-frame))))
diff --git a/lisp/xt-mouse.el b/lisp/xt-mouse.el
index 4ccd35d5277..2e927c0e32e 100644
--- a/lisp/xt-mouse.el
+++ b/lisp/xt-mouse.el
@@ -63,9 +63,13 @@ https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)."
           (is-move (eq 'mouse-movement ev-command))
           (is-down (string-match "down-" (symbol-name ev-command))))
 
-      ;; Mouse events symbols must have an 'event-kind property with
-      ;; the value 'mouse-click.
-      (when ev-command (put ev-command 'event-kind 'mouse-click))
+      ;; Mouse events symbols must have an 'event-kind property set.
+      ;; Most of them use the value 'mouse-click, but 'mouse-movement has
+      ;; a different value.  See head_table in keyboard.c. (bug#67457)
+      (when ev-command (put ev-command 'event-kind
+                            (if (eq ev-command 'mouse-movement)
+                                'mouse-movement
+                              'mouse-click)))
 
       (cond
        ((null event) nil)              ;Unknown/bogus byte sequence!
diff --git a/src/ChangeLog.11 b/src/ChangeLog.11
index b1e476e56fd..7e21ca3ed30 100644
--- a/src/ChangeLog.11
+++ b/src/ChangeLog.11
@@ -2029,7 +2029,7 @@
        (update_frame_tool_bar): Calculate tool-bar style once per call.
        Instead of hiding text labels, omit them.  Don't use
        xg_show_toolbar_item; create new GtkToolItems from scratch if
-       necessary, instead of trying to re-use them.  This avoids an
+       necessary, instead of trying to reuse them.  This avoids an
        annoying animation when changing tool-bars.
 
 2010-12-31  Jan Djärv  <jan.h.d@swipnet.se>
@@ -2048,7 +2048,7 @@
        (ns_set_name): Call ns_set_name_internal.
        (x_explicitly_set_name): Remove call to ns_set_name_iconic.
        (x_implicitly_set_name): Ditto.
-       (x_set_title): Remove commet about EXPLICIT.  Call ns_set_name_internal.
+       (x_set_title): Remove comment about EXPLICIT.  Call 
ns_set_name_internal.
        (ns_set_name_as_filename): Encode name with ENCODE_UTF_8 (Bug#7517).
 
 2010-12-29  Štěpán Němec  <stepnem@gmail.com>  (tiny change)
@@ -9435,7 +9435,7 @@
        continuation line, and start looking for a suitable row from
        there.
 
-       * term.c (append_glyph): Reverse glyphs by pre-pending them,
+       * term.c (append_glyph): Reverse glyphs by prepending them,
        rather than appending, if the glyph_row's reversed_p flag is set.
        Set the resolved_level and bidi_type members of each glyph.
 
diff --git a/src/ChangeLog.13 b/src/ChangeLog.13
index d9736479a04..2f44ba02d98 100644
--- a/src/ChangeLog.13
+++ b/src/ChangeLog.13
@@ -5464,7 +5464,7 @@
        (set_horizontal_scroll_bar): New function.
        (redisplay_window): Set ignore_mouse_drag_p when tool bar has
        more than one line.  Handle horizontal scroll bars.
-       (note_mouse_highlight): Handle horizontal scrol bars.
+       (note_mouse_highlight): Handle horizontal scroll bars.
        (expose_frame): Set dimensions of XRectangle from frame's text
        sizes.
        (Vvoid_text_area_pointer): Update doc-string.
@@ -8437,7 +8437,7 @@
 
        * xdisp.c (syms_of_xdisp): Doc clarification (bug#15657).
 
-       * keyboard.c (Frecursive_edit): Say more precicely how throwing
+       * keyboard.c (Frecursive_edit): Say more precisely how throwing
        `exit' works (bug#15865).
 
 2014-02-07  Martin Rudalics  <rudalics@gmx.at>
@@ -16678,7 +16678,7 @@
 
 2013-05-27  Eli Zaretskii  <eliz@gnu.org>
 
-       * xdisp.c (pos_visible_p): When CHARPOS is displayed frrom a
+       * xdisp.c (pos_visible_p): When CHARPOS is displayed from a
        display vector, and we backtrack, handle the case that the
        previous character position is also displayed from a display
        vector or covered by a display string or image.  (Bug#14476)
diff --git a/src/ChangeLog.8 b/src/ChangeLog.8
index 1f479a89ed8..f50b8d134c3 100644
--- a/src/ChangeLog.8
+++ b/src/ChangeLog.8
@@ -10802,7 +10802,7 @@
        (display_mode_element): Ditto.
        (echo_area_display): Don't display if frame has no pools yet.
        (echo_area_display): Work with window matrix for mini window.
-       (redisplay_window): Use window marix for mini window.
+       (redisplay_window): Use window matrix for mini window.
        (display_text_line): Assume HPOS and VPOS are window relative and
        use that for DISPLAY_STRING.
 
diff --git a/src/ChangeLog.9 b/src/ChangeLog.9
index d005b51604b..09210f8eea9 100644
--- a/src/ChangeLog.9
+++ b/src/ChangeLog.9
@@ -11622,7 +11622,7 @@
        (set_font_frame_param): If `font' is specified in lface, use it.
        (Finternal_get_lisp_face_attribute): Handle `font' slot in lface.
        (lface_same_font_attributes_p): Likewise.
-       (make_realized_face): Arguent changed.  Caller changed.  Set
+       (make_realized_face): Argument changed.  Caller changed.  Set
        face->ascii_face to face itself.
        (free_realized_face): Free face->fontset if face is for ASCII.
        (face_suitable_for_iso8859_1_p, face_suitable_for_charset_p)
diff --git a/src/android.c b/src/android.c
index 7ca5eab817c..7a393f8f56d 100644
--- a/src/android.c
+++ b/src/android.c
@@ -1455,6 +1455,18 @@ NATIVE_NAME (setEmacsParams) (JNIEnv *env, jobject 
object,
      the possibility of Java locating libemacs later.  */
   setenv ("EMACS_LD_LIBRARY_PATH", android_lib_dir, 1);
 
+  /* If the system is Android 5.0 or later, set LANG to en_US.utf8,
+     which is understood by the C library.  In other instances set it
+     to C, a meaningless value, for good measure.  */
+
+  if (emacs_service_object)
+    {
+      if (api_level >= 21)
+       setenv ("LANG", "en_US.utf8", 1);
+      else
+       setenv ("LANG", "C", 1);
+    }
+
   /* Make a reference to the Emacs service.  */
 
   if (emacs_service_object)
@@ -2767,7 +2779,7 @@ android_destroy_handle (android_handle handle)
 
   /* Just clear any exception thrown.  If destroying the handle
      fails from an out-of-memory error, then Emacs loses some
-     resources, but that is not as big deal as signalling.  */
+     resources, but that is not as big deal as signaling.  */
   (*android_java_env)->ExceptionClear (android_java_env);
 
   /* Delete the global reference regardless of any error.  */
@@ -5785,7 +5797,7 @@ android_check_string (Lisp_Object text)
    better represent the UCS-16 based Java String format, and to let
    strings contain NULL characters while remaining valid C strings:
    NULL bytes are encoded as two-byte sequences, and Unicode surrogate
-   pairs encoded as two-byte sequences are prefered to four-byte
+   pairs encoded as two-byte sequences are preferred to four-byte
    sequences when encoding characters above the BMP.  */
 
 int
diff --git a/src/androidfns.c b/src/androidfns.c
index 31a4924e34d..14561afe29a 100644
--- a/src/androidfns.c
+++ b/src/androidfns.c
@@ -27,6 +27,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "keyboard.h"
 #include "buffer.h"
 #include "androidgui.h"
+#include "pdumper.h"
 
 #ifndef ANDROID_STUBIFY
 
@@ -3170,6 +3171,191 @@ android_set_preeditarea (struct window *w, int x, int y)
 
 
 
+#ifndef ANDROID_STUBIFY
+
+static void
+syms_of_androidfns_for_pdumper (void)
+{
+  jclass locale;
+  jmethodID method;
+  jobject object;
+  jstring string;
+  Lisp_Object language, country, script, variant;
+  const char *data;
+
+  /* Find the Locale class.  */
+
+  locale = (*android_java_env)->FindClass (android_java_env,
+                                          "java/util/Locale");
+  if (!locale)
+    emacs_abort ();
+
+  /* And the method from which the default locale can be
+     extracted.  */
+
+  method = (*android_java_env)->GetStaticMethodID (android_java_env,
+                                                  locale,
+                                                  "getDefault",
+                                                  "()Ljava/util/Locale;");
+  if (!method)
+    emacs_abort ();
+
+  /* Retrieve the default locale.  */
+
+  object = (*android_java_env)->CallStaticObjectMethod (android_java_env,
+                                                       locale, method);
+  android_exception_check_1 (locale);
+
+  if (!object)
+    emacs_abort ();
+
+  /* Retrieve its language field.  Each of these methods is liable to
+     return the empty string, though if language is empty, the locale
+     is malformed.  */
+
+  method = (*android_java_env)->GetMethodID (android_java_env, locale,
+                                            "getLanguage",
+                                            "()Ljava/lang/String;");
+  if (!method)
+    emacs_abort ();
+
+  string = (*android_java_env)->CallObjectMethod (android_java_env, object,
+                                                 method);
+  android_exception_check_2 (object, locale);
+
+  if (!string)
+    language = empty_unibyte_string;
+  else
+    {
+      data = (*android_java_env)->GetStringUTFChars (android_java_env,
+                                                    string, NULL);
+      android_exception_check_3 (object, locale, string);
+
+      if (!data)
+       language = empty_unibyte_string;
+      else
+       {
+         language = build_unibyte_string (data);
+         (*android_java_env)->ReleaseStringUTFChars (android_java_env,
+                                                     string, data);
+       }
+    }
+
+  /* Delete the reference to this string.  */
+  ANDROID_DELETE_LOCAL_REF (string);
+
+  /* Proceed to retrieve the country code.  */
+
+  method = (*android_java_env)->GetMethodID (android_java_env, locale,
+                                            "getCountry",
+                                            "()Ljava/lang/String;");
+  if (!method)
+    emacs_abort ();
+
+  string = (*android_java_env)->CallObjectMethod (android_java_env, object,
+                                                 method);
+  android_exception_check_2 (object, locale);
+
+  if (!string)
+    country = empty_unibyte_string;
+  else
+    {
+      data = (*android_java_env)->GetStringUTFChars (android_java_env,
+                                                    string, NULL);
+      android_exception_check_3 (object, locale, string);
+
+      if (!data)
+       country = empty_unibyte_string;
+      else
+       {
+         country = build_unibyte_string (data);
+         (*android_java_env)->ReleaseStringUTFChars (android_java_env,
+                                                     string, data);
+       }
+    }
+
+  ANDROID_DELETE_LOCAL_REF (string);
+
+  /* Proceed to retrieve the script.  */
+
+  if (android_get_current_api_level () < 21)
+    script = empty_unibyte_string;
+  else
+    {
+      method = (*android_java_env)->GetMethodID (android_java_env, locale,
+                                                "getScript",
+                                                "()Ljava/lang/String;");
+      if (!method)
+       emacs_abort ();
+
+      string = (*android_java_env)->CallObjectMethod (android_java_env,
+                                                     object, method);
+      android_exception_check_2 (object, locale);
+
+      if (!string)
+       script = empty_unibyte_string;
+      else
+       {
+         data = (*android_java_env)->GetStringUTFChars (android_java_env,
+                                                        string, NULL);
+         android_exception_check_3 (object, locale, string);
+
+         if (!data)
+           script = empty_unibyte_string;
+         else
+           {
+             script = build_unibyte_string (data);
+             (*android_java_env)->ReleaseStringUTFChars (android_java_env,
+                                                         string, data);
+           }
+       }
+    }
+
+  ANDROID_DELETE_LOCAL_REF (string);
+
+  /* And variant.  */
+
+  method = (*android_java_env)->GetMethodID (android_java_env, locale,
+                                            "getVariant",
+                                            "()Ljava/lang/String;");
+  if (!method)
+    emacs_abort ();
+
+  string = (*android_java_env)->CallObjectMethod (android_java_env, object,
+                                                 method);
+  android_exception_check_2 (object, locale);
+
+  if (!string)
+    variant = empty_unibyte_string;
+  else
+    {
+      data = (*android_java_env)->GetStringUTFChars (android_java_env,
+                                                    string, NULL);
+      android_exception_check_3 (object, locale, string);
+
+      if (!data)
+        variant = empty_unibyte_string;
+      else
+       {
+         variant = build_unibyte_string (data);
+         (*android_java_env)->ReleaseStringUTFChars (android_java_env,
+                                                     string, data);
+       }
+    }
+
+  /* Delete the reference to this string.  */
+  ANDROID_DELETE_LOCAL_REF (string);
+
+  /* And other remaining local references.  */
+  ANDROID_DELETE_LOCAL_REF (object);
+  ANDROID_DELETE_LOCAL_REF (locale);
+
+  /* Set Vandroid_os_language.  */
+  Vandroid_os_language = list4 (language, country, script, variant);
+}
+
+#endif /* ANDROID_STUBIFY */
+
 void
 syms_of_androidfns (void)
 {
@@ -3313,6 +3499,25 @@ element that is activated for a given number of 
milliseconds upon the
 bell being rung.  */);
   android_keyboard_bell_duration = 50;
 
+  DEFVAR_LISP ("android-os-language", Vandroid_os_language,
+    doc: /* A list representing the configured system language on Android.
+This list has four elements: LANGUAGE, COUNTRY, SCRIPT and VARIANT, where:
+
+LANGUAGE and COUNTRY are ISO language and country codes identical to
+those found in POSIX locale specifications.
+
+SCRIPT is an ISO 15924 script tag, representing the script used
+if available, or if required to disambiguate between distinct
+writing systems for the same combination of language and country.
+
+VARIANT is an arbitrary string representing the variant of the
+LANGUAGE or SCRIPT.
+
+Each of these fields might be empty or nil, but the locale is invalid
+if LANGUAGE is empty.  Users of this variable should consider the
+language to be US English if LANGUAGE is empty.  */);
+  Vandroid_os_language = Qnil;
+
   /* Functions defined.  */
   defsubr (&Sx_create_frame);
   defsubr (&Sxw_color_defined_p);
@@ -3363,5 +3568,7 @@ bell being rung.  */);
   staticpro (&tip_dx);
   tip_dy = Qnil;
   staticpro (&tip_dy);
+
+  pdumper_do_now_and_after_load (syms_of_androidfns_for_pdumper);
 #endif /* !ANDROID_STUBIFY */
 }
diff --git a/src/androidselect.c b/src/androidselect.c
index f7988db0520..e7a6ee258a8 100644
--- a/src/androidselect.c
+++ b/src/androidselect.c
@@ -299,7 +299,7 @@ data type available from the clipboard.  */)
                                                bytes_array);
   for (i = 0; i < length; ++i)
     {
-      /* Retireve the MIME type.  */
+      /* Retrieve the MIME type.  */
       bytes
        = (*android_java_env)->GetObjectArrayElement (android_java_env,
                                                      bytes_array, i);
diff --git a/src/androidterm.c b/src/androidterm.c
index cfb64cd69a0..c3a04fd3cfb 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -6101,7 +6101,7 @@ android_update_selection (struct frame *f, struct window 
*w)
   else
     start = -1, end = -1;
 
-  /* Now constrain START and END to the maximium size of a Java
+  /* Now constrain START and END to the maximum size of a Java
      integer.  */
   start = min (start, TYPE_MAXIMUM (jint));
   end = min (end, TYPE_MAXIMUM (jint));
@@ -6238,7 +6238,7 @@ android_reset_conversion (struct frame *f)
 
   android_reset_ic (FRAME_ANDROID_WINDOW (f), mode);
 
-  /* Clear extracted text flags.  Since the IM has been reinitialised,
+  /* Clear extracted text flags.  Since the IM has been reinitialized,
      it should no longer be displaying extracted text.  */
   FRAME_ANDROID_OUTPUT (f)->extracted_text_flags = 0;
 
diff --git a/src/androidterm.h b/src/androidterm.h
index e75d46b1dfb..9830cc4364d 100644
--- a/src/androidterm.h
+++ b/src/androidterm.h
@@ -262,7 +262,7 @@ struct android_output
      text''.  */
   int extracted_text_flags;
 
-  /* Token asssociated with that request.  */
+  /* Token associated with that request.  */
   int extracted_text_token;
 
   /* The number of characters of extracted text wanted by the IM.  */
diff --git a/src/androidvfs.c b/src/androidvfs.c
index 51558d2a375..3b7fb731e86 100644
--- a/src/androidvfs.c
+++ b/src/androidvfs.c
@@ -407,7 +407,7 @@ android_init_fd_class (JNIEnv *env)
    values are prohibitively slow, but smaller values can't face up to
    some long file names within several nested layers of directories.
 
-   Buffers holding components or other similar file name constitutents
+   Buffers holding components or other similar file name constituents
    which don't represent SAF files must continue to use PATH_MAX, for
    that is the restriction imposed by the Unix file system.  */
 
@@ -4179,7 +4179,7 @@ android_saf_stat (const char *uri_name, const char 
*id_name,
 }
 
 /* Detect if Emacs has access to the document designated by the the
-   documen ID ID_NAME within the tree URI_NAME.  If ID_NAME is NULL,
+   document ID ID_NAME within the tree URI_NAME.  If ID_NAME is NULL,
    use the document ID in URI_NAME itself.
 
    If WRITABLE, also check that the file is writable, which is true
@@ -6427,7 +6427,7 @@ android_root_name (struct android_vnode *vnode, char 
*name,
   if (!component_end)
     component_end = name + length;
   else
-    /* Move past the spearator character.  */
+    /* Move past the separator character.  */
     component_end++;
 
   /* Now, find out if the first component is a special vnode; if so,
@@ -7172,7 +7172,7 @@ android_readlinkat (int dirfd, const char *restrict 
pathname,
    while file streams also require ownership over file descriptors
    they are created on behalf of.
 
-   Detaching the parcel file descriptor linked to FD consequentially
+   Detaching the parcel file descriptor linked to FD consequently
    prevents the owner from being notified when it is eventually
    closed, but for now that hasn't been demonstrated to be problematic
    yet, as Emacs doesn't write to file streams.  */
diff --git a/src/conf_post.h b/src/conf_post.h
index f31e012dc6e..43ec5265ec6 100644
--- a/src/conf_post.h
+++ b/src/conf_post.h
@@ -96,7 +96,7 @@ typedef bool bool_bf;
 #ifdef emacs
 /* We include stdlib.h here, because Gnulib's stdlib.h might redirect
    'free' to its replacement, and we want to avoid that in unexec
-   builds.  Inclduing it here will render its inclusion after config.h
+   builds.  Including it here will render its inclusion after config.h
    a no-op.  */
 # if (defined DARWIN_OS && defined HAVE_UNEXEC) || defined HYBRID_MALLOC
 #  include <stdlib.h>
diff --git a/src/eval.c b/src/eval.c
index 1b8e0c248e2..daeb279fde7 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -3855,10 +3855,18 @@ get_backtrace_starting_at (Lisp_Object base)
 
   if (!NILP (base))
     { /* Skip up to `base'.  */
+      int offset = 0;
+      if (CONSP (base) && FIXNUMP (XCAR (base)))
+        {
+          offset = XFIXNUM (XCAR (base));
+          base = XCDR (base);
+        }
       base = Findirect_function (base, Qt);
       while (backtrace_p (pdl)
              && !EQ (base, Findirect_function (backtrace_function (pdl), Qt)))
         pdl = backtrace_next (pdl);
+      while (backtrace_p (pdl) && offset-- > 0)
+        pdl = backtrace_next (pdl);
     }
 
   return pdl;
@@ -3898,13 +3906,14 @@ backtrace_frame_apply (Lisp_Object function, union 
specbinding *pdl)
     }
 }
 
-DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 2, 0,
+DEFUN ("backtrace-debug", Fbacktrace_debug, Sbacktrace_debug, 2, 3, 0,
        doc: /* Set the debug-on-exit flag of eval frame LEVEL levels down to 
FLAG.
+LEVEL and BASE specify the activation frame to use, as in `backtrace-frame'.
 The debugger is entered when that frame exits, if the flag is non-nil.  */)
-  (Lisp_Object level, Lisp_Object flag)
+  (Lisp_Object level, Lisp_Object flag, Lisp_Object base)
 {
   CHECK_FIXNUM (level);
-  union specbinding *pdl = get_backtrace_frame(level, Qnil);
+  union specbinding *pdl = get_backtrace_frame (level, base);
 
   if (backtrace_p (pdl))
     set_backtrace_debug_on_exit (pdl, !NILP (flag));
@@ -4391,7 +4400,10 @@ If due to frame exit, args are `exit' and the value 
being returned;
  this function's value will be returned instead of that.
 If due to error, args are `error' and a list of the args to `signal'.
 If due to `apply' or `funcall' entry, one arg, `lambda'.
-If due to `eval' entry, one arg, t.  */);
+If due to `eval' entry, one arg, t.
+IF the desired entry point of the debugger is higher in the call stack,
+it can can be specified with the keyword argument `:backtrace-base'
+whose format should be the same as the BASE arg of `backtrace-frame'.  */);
   Vdebugger = Qdebug_early;
 
   DEFVAR_LISP ("signal-hook-function", Vsignal_hook_function,
diff --git a/src/fileio.c b/src/fileio.c
index 51937e6d765..64f255a355b 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -203,7 +203,7 @@ check_vfs_filename (Lisp_Object encoded, const char *reason)
 #ifdef HAVE_LIBSELINUX
 
 /* Return whether SELinux is enabled and pertinent to FILE.  Provide
-   for cases where FILE is or is a constitutent of a special
+   for cases where FILE is or is a constituent of a special
    directory, such as /assets or /content on Android.  */
 
 static bool
diff --git a/src/image.c b/src/image.c
index 7621d71d5b5..472988633e2 100644
--- a/src/image.c
+++ b/src/image.c
@@ -11787,7 +11787,7 @@ svg_css_length_to_pixels (RsvgLength length, double 
dpi, int font_size)
 
         If we do set explicit width and height values in the image
         spec, this will work out correctly as librsvg will still
-        honour the percentage sizes in its final rendering no matter
+        honor the percentage sizes in its final rendering no matter
         what size we make the image.  */
       value = 0;
       break;
@@ -12055,7 +12055,7 @@ svg_load_image (struct frame *f, struct image *img, 
char *contents,
       }
 
 #if HAVE_NTGUI
-    /* Windows stores the image colours in BGR format, and SVG expects
+    /* Windows stores the image colors in BGR format, and SVG expects
        them in RGB.  */
     foreground = (foreground & 0x0000FF) << 16
       | (foreground & 0xFF0000) >> 16
diff --git a/src/itree.c b/src/itree.c
index 259cc99d3af..5aefea528f5 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -74,7 +74,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 
    Consider the case where next-overlay-change is called at POS, all
    interval BEG positions are less than pos POS and all interval END
-   posistions are after.  These END positions have no order, and so
+   positions are after.  These END positions have no order, and so
    *every* interval must be examined.  This is at least O(N).  The
    previous-overlay-change case is similar.  The root issue is that
    the iterative "narrowing" approach is not guaranteed to reduce the
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index 461c9d6d899..9a87820f82b 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -6259,7 +6259,7 @@ symbol_to_drag_action (Lisp_Object act)
   if (NILP (act))
     return GDK_ACTION_DEFAULT;
 
-  signal_error ("Invalid drag acction", act);
+  signal_error ("Invalid drag action", act);
 }
 
 static Lisp_Object
diff --git a/src/print.c b/src/print.c
index 45173272002..1483667ad1a 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1618,7 +1618,7 @@ print_bool_vector (Lisp_Object obj, Lisp_Object 
printcharfun)
   ptrdiff_t real_size_in_bytes = size_in_bytes;
   unsigned char *data = bool_vector_uchar_data (obj);
 
-  char buf[sizeof "#&" + INT_STRLEN_BOUND (ptrdiff_t)];
+  char buf[sizeof "#&\"" + INT_STRLEN_BOUND (ptrdiff_t)];
   int len = sprintf (buf, "#&%"pI"d\"", size);
   strout (buf, len, len, printcharfun);
 
diff --git a/src/process.c b/src/process.c
index e49bf812169..89bccd90679 100644
--- a/src/process.c
+++ b/src/process.c
@@ -7520,7 +7520,7 @@ handle_child_signal (int sig)
 
                   emacs_unlink is not async signal safe because
                   deleting files from content providers must proceed
-                  through Java code.  Consequentially, if XCDR (head)
+                  through Java code.  Consequently, if XCDR (head)
                   lies on a content provider it will not be removed,
                   which is a bug.  */
                unlink (SSDATA (XCDR (head)));
diff --git a/src/regex-emacs.c b/src/regex-emacs.c
index cb4fbd58faa..19bec537130 100644
--- a/src/regex-emacs.c
+++ b/src/regex-emacs.c
@@ -2824,7 +2824,7 @@ group_in_compile_stack (compile_stack_type compile_stack, 
regnum_t regnum)
 
 /* Iterate through all the char-matching operations directly reachable from P.
    This is the inner loop of `forall_firstchar`, which see.
-   LOOP_BEG..LOOP_END delimit the currentl "block" of code (we assume
+   LOOP_BEG..LOOP_END delimit the currently "block" of code (we assume
    the code is made of syntactically nested loops).
    LOOP_END is blindly assumed to be "safe".
    To guarantee termination, at each iteration, either LOOP_BEG should
diff --git a/src/sfnt.c b/src/sfnt.c
index 8ec19290859..131b4fd409c 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -67,6 +67,19 @@ xmalloc (size_t size)
   return ptr;
 }
 
+MAYBE_UNUSED static void *
+xzalloc (size_t size)
+{
+  void *ptr;
+
+  ptr = calloc (1, size);
+
+  if (!ptr)
+    abort ();
+
+  return ptr;
+}
+
 static void *
 xrealloc (void *ptr, size_t size)
 {
@@ -2783,7 +2796,7 @@ sfnt_decompose_compound_glyph (struct sfnt_glyph *glyph,
       else
        {
          /* The offset is determined by matching a point location in
-            a preceeding component with a point location in the
+            a preceding component with a point location in the
             current component.  The index of the point in the
             previous component can be determined by adding
             component->argument1.a or component->argument1.c to
@@ -3487,12 +3500,18 @@ sfnt_build_append (int flags, sfnt_fixed x, sfnt_fixed 
y)
 {
   struct sfnt_glyph_outline *outline;
 
+  outline = build_outline_context.outline;
+
   if (x == build_outline_context.x
-      && y == build_outline_context.y)
+      && y == build_outline_context.y
+      /* If the outline is presently empty, the first move_to must be
+        recorded even if its X and Y are set to origin.  Without this
+        initial vertex, edges will be generated from the next vertex
+        onward, and thus be misaligned.  */
+      && outline->outline_used)
     /* Ignore redundant motion.  */
     return build_outline_context.outline;
 
-  outline = build_outline_context.outline;
   outline->outline_used++;
 
   /* See if the outline has to be extended.  Checking for overflow
@@ -3886,11 +3905,11 @@ sfnt_curve_is_flat (struct sfnt_point control0,
   h.x = endpoint.x - control0.x;
   h.y = endpoint.y - control0.y;
 
-  /* 2.0 is a constant describing the area covered at which point the
-     curve is considered "flat".  */
+  /* 1.0 is a constant representing the area covered at which point
+     the curve is considered "flat".  */
   return (abs (sfnt_mul_fixed (g.x, h.y)
               - sfnt_mul_fixed (g.y, h.x))
-         <= 0400000);
+         <= 0200000);
 }
 
 /* Recursively split the splines in the bezier curve formed from
@@ -4205,7 +4224,6 @@ sfnt_build_outline_edges (struct sfnt_glyph_outline 
*outline,
 
       /* Compute the step X.  This is how much X changes for each
         increase in Y.  */
-
       step_x = sfnt_div_fixed (dx, dy);
       edges[edge].next = NULL;
 
@@ -4295,7 +4313,6 @@ sfnt_poly_edges (struct sfnt_edge *edges, size_t size,
   /* Step down line by line.  Find active edges.  */
 
   y = edges[0].bottom;
-  active = 0;
   active = NULL;
   e = 0;
 
@@ -4593,6 +4610,930 @@ sfnt_raster_glyph_outline (struct sfnt_glyph_outline 
*outline)
 
 
 
+#define sfnt_add(a, b)                         \
+  ((int) ((unsigned int) (a) + (unsigned int) (b)))
+
+#define sfnt_sub(a, b)                         \
+  ((int) ((unsigned int) (a) - (unsigned int) (b)))
+
+#define sfnt_mul(a, b)                         \
+  ((int) ((unsigned int) (a) * (unsigned int) (b)))
+
+
+
+/* Exact coverage scaler.
+
+   The foregoing routines calculate partial coverage for each pixel by
+   increasing each span in increments finer than a single pixel, then
+   merging active spans into the raster.
+
+   Experience has proven this yields imperfect display results,
+   particularly when combined with glyph instruction code which aligns
+   points in a certain and as yet undetermined manner.
+
+   The scaler implemented in this page attains greater precision,
+   generating at length an array of scanlines, in which each is
+   represented by a list of steps.  Each step holds an X coordinate
+   and a coverage value, which contributes to the coverage of each
+   pixel within the scanline rightwards or equal to the pixel with its
+   X coordinate.
+
+   Such a coverage value can be positive or negative; when the winding
+   direction of the span it derives from is positive, so is the
+   coverage value, that the pixels to its right (thus further into the
+   polygon it demarcates) might be painted in.  In the other case, the
+   value is negative, thus negating the effect of preceding steps and
+   marking the outer boundary of the section of the polygon's
+   intersection with the scanline.
+
+   The procedure for producing this array of scanlines is largely an
+   adaptation of that which sfnt_poly_edges implements; in particular
+   the process of sorting and filtering edges remains untouched.
+
+   Rather than advancing through the edges SFNT_POLY_STEP at a time,
+   the edges are iterated over scanline-by-scanline.  Every edge
+   overlapping with a particular scanline is considered piecemeal to
+   generate its array of steps.
+
+   An edge might overlap pixels within the scanline in one of four
+   fashions; each is illustrated with a graphic below:
+
+   +--------ee-----+------------------------------------------------+ (I)
+   |      ee.......|................................................|
+   |    ee.........|................................................|
+   |  ee...........|................................................|
+   |ee.............|................................................|
+  ee---------------+------------------------------------------------+
+
+   In this instance, the edge partially overlaps its first pixel, but
+   the remainder all receive complete coverage.
+
+   +---------------+---------eeeeee+--------------------------------+ (II)
+   |               |   eeeeee......|................................|
+   |                     eeeee............|................................|
+   |        eeeeee.|...............|................................|
+   |  eeeeee.......|...............|................................|
+   eee-------------+---------------+--------------------------------+
+
+   In this instance, the edge partially overlaps two or more pixels on
+   this scanline.  These pixels are referred to as a run.
+
+   +---------------+---------------+----------------+---------------+ (III)
+   |       eeeeeee.|...............|................|...............|
+   |            eeeeeeee..|...............|................|...............|
+   |   eeeeeeee....|...............|................|...............|
+   |  eeeeeee......|...............|................|...............|
+   +---------------+---------------+----------------+---------------+
+
+   This instance is much like the first instance, save that the
+   covered vertical area does not span the entire scanline.
+
+   +---------------+---------------+----------------+---------------+ (IV)
+   |               |               |                | eeeeeeeeeee...|
+   |                      |              eeeeeeeeeeeeeeeeeeeeeeeeeeeeeee...|
+   |          eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee|...............|
+   |eeeeeeeeeeeeeeeeeeeeeee........|................|...............|
+   +---------------+---------------+----------------+---------------+
+
+   And this the second, again with the same distinction therefrom.
+
+   In each of these instances, a trapezoid is formed within every
+   pixel of the scanline, between:
+
+     - The point of the span's entry into the first pixel, either that
+       point itself or, for subsequent pixels, its projection onto
+       those pixels.
+
+     - The point of the span's exit or its termination.
+
+     - Both those points projected into the outer boundary of the
+       pertinent pixel.
+
+   The proportion formed by the area of this trapezoid and that of the
+   pixel then constitutes the coverage value to be recorded.  */
+
+/* Structure representing a step, as above.  */
+
+struct sfnt_step
+{
+  /* The next step in this list.  */
+  struct sfnt_step *next;
+
+  /* X coordinate of the step.  This value affects all pixels at and
+     beyond this X coordinate.  */
+  int x;
+
+  /* Coverage value between -1 and 1.  */
+  float coverage;
+};
+
+/* Structure representing an array of steps, one for each
+   scanline.  */
+
+struct sfnt_step_raster
+{
+  /* Number of scanlines within this raster.  */
+  size_t scanlines;
+
+  /* Array of steps with one element for each scanline.  */
+  struct sfnt_step **steps;
+
+  /* Linked list of chunks of steps allocated for this raster.  */
+  struct sfnt_step_chunk *chunks;
+};
+
+enum
+  {
+    SFNT_BLOCK_STEPS = 128,
+  };
+
+/* Structure representing a block of steps, which are allocated
+   SFNT_BLOCK_STEPS at a time.  */
+
+struct sfnt_step_chunk
+{
+  /* The next chunk in this list, or NULL.  */
+  struct sfnt_step_chunk *next;
+
+  /* Number of steps used within this chunk thus far.  */
+  size_t nused;
+
+  /* The steps themselves.  */
+  struct sfnt_step steps[SFNT_BLOCK_STEPS];
+};
+
+/* Structure representing an edge as consumed by the exact coverage
+   scaler.  This structure is much like struct sfnt_edge, albeit with
+   all fractionals replaced by floating point numbers and an extra
+   field holding a Y delta.  */
+
+struct sfnt_fedge
+{
+  /* Next edge in this chain.  */
+  struct sfnt_fedge *next;
+
+  /* Winding direction.  1 if clockwise, -1 if counterclockwise.  */
+  int winding;
+
+  /* X position, top and bottom of edges.  */
+  float x, top, bottom;
+
+  /* Amount to move X by upon each change of Y, and vice versa.  */
+  float step_x, step_y;
+};
+
+typedef void (*sfnt_fedge_proc) (struct sfnt_fedge *, size_t,
+                                void *);
+
+/* Build a list of edges for each contour in OUTLINE, displacing each
+   edge by xmin and ymin.  Call EDGE_PROC with DCONTEXT and the edges
+   produced as arguments.  */
+
+static void
+sfnt_build_outline_fedges (struct sfnt_glyph_outline *outline,
+                          sfnt_fedge_proc edge_proc, void *dcontext)
+{
+  struct sfnt_fedge *edges;
+  size_t i, edge, next_vertex;
+  sfnt_fixed dx, dy, step_x, step_y, ymin, xmin;
+  size_t top, bottom;
+
+  edges = alloca (outline->outline_used * sizeof *edges);
+  edge = 0;
+
+  /* ymin and xmin must be the same as the offset used to set offy and
+     offx in rasters.  */
+  ymin = sfnt_floor_fixed (outline->ymin);
+  xmin = sfnt_floor_fixed (outline->xmin);
+
+  for (i = 0; i < outline->outline_used; ++i)
+    {
+      /* Set NEXT_VERTEX to the next point (vertex) in this contour.
+
+        If i is past the end of the contour, then don't build edges
+        for this point.  */
+      next_vertex = i + 1;
+
+      if (next_vertex == outline->outline_used
+         || !(outline->outline[next_vertex].flags
+              & SFNT_GLYPH_OUTLINE_LINETO))
+       continue;
+
+      /* Skip past horizontal vertices.  */
+      if (outline->outline[next_vertex].y == outline->outline[i].y)
+       continue;
+
+      /* Figure out the winding direction.  */
+      if (outline->outline[next_vertex].y < outline->outline[i].y)
+       /* Vector will cross imaginary ray from its bottom from the
+          left of the ray.  Winding is thus 1.  */
+       edges[edge].winding = 1;
+      else
+       /* Moving clockwise.  Winding is thus -1.  */
+       edges[edge].winding = -1;
+
+      /* Figure out the top and bottom values of this edge.  If the
+        next edge is below, top is here and bot is the edge below.
+        If the next edge is above, then top is there and this is the
+        bottom.  */
+
+      if (outline->outline[next_vertex].y < outline->outline[i].y)
+       {
+         /* End of edge is below this one (keep in mind this is a
+            cartesian coordinate system, so smaller values are below
+            larger ones.) */
+         top = i;
+         bottom = next_vertex;
+       }
+      else
+       {
+         /* End of edge is above this one.  */
+         bottom = i;
+         top = next_vertex;
+       }
+
+      /* Record the edge.  Rasterization happens from bottom to
+        up, so record the X at the bottom.  */
+      dx = (outline->outline[top].x - outline->outline[bottom].x);
+      dy = abs (outline->outline[top].y
+               - outline->outline[bottom].y);
+
+      /* Compute the step X.  This is how much X changes for each
+        increase in Y.  */
+      step_x = sfnt_div_fixed (dx, dy);
+
+      /* And the step Y, which is the amount of movement to Y an
+        increase in X will incur.  */
+      step_y = dx ? sfnt_div_fixed (dy, dx) : 0;
+
+      /* Save information computed above into the edge.  */
+      edges[edge].top
+       = sfnt_fixed_float (outline->outline[top].y - ymin);
+      edges[edge].bottom
+       = sfnt_fixed_float (outline->outline[bottom].y - ymin);
+      edges[edge].x
+       = sfnt_fixed_float (outline->outline[bottom].x - xmin);
+      edges[edge].step_x = sfnt_fixed_float (step_x);
+      edges[edge].step_y = sfnt_fixed_float (step_y);
+      edges[edge].next = NULL;
+
+      /* Increment the edge index.  */
+      edge++;
+    }
+
+  if (edge)
+    edge_proc (edges, edge, dcontext);
+}
+
+typedef void (*sfnt_step_raster_proc) (struct sfnt_step_raster *, void *);
+
+/* Append a step with the supplied COVERAGE at X to the sorted list of
+   scanline steps within the container RASTER.  Y is the scanline to
+   append to.  */
+
+static void
+sfnt_insert_raster_step (struct sfnt_step_raster *raster,
+                        int x, float coverage, size_t scanline)
+{
+  struct sfnt_step_chunk *chunk;
+  struct sfnt_step *step, **p_next;
+
+  if (scanline >= raster->scanlines)
+    return;
+
+  if (x < 0)
+    x = 0;
+
+  /* Search within RASTER->steps[scanline] for a step at X.  */
+
+  p_next = &raster->steps[scanline];
+
+  while ((step = *p_next))
+    {
+      if (step->x > x)
+       break;
+
+      if (step->x == x)
+       goto found;
+
+      p_next = &step->next;
+    }
+
+  if (!raster->chunks
+      || raster->chunks->nused == SFNT_BLOCK_STEPS)
+    {
+      /* All chunks have been consumed, and consequently a new chunk
+        must be allocated.  */
+      chunk = xmalloc (sizeof *chunk);
+      chunk->next = raster->chunks;
+      chunk->nused = 0;
+      raster->chunks = chunk;
+    }
+  else
+    chunk = raster->chunks;
+
+  step          = &chunk->steps[chunk->nused++];
+  step->next    = *p_next;
+  *p_next       = step;
+  step->x       = x;
+  step->coverage = 0;
+
+ found:
+  step->coverage += coverage;
+}
+
+/* Sort an array of SIZE edges to increase by bottom Y position, in
+   preparation for building spans.
+
+   Insertion sort is used because there are usually not very many
+   edges, and anything larger would bloat up the code.  */
+
+static void
+sfnt_fedge_sort (struct sfnt_fedge *edges, size_t size)
+{
+  ssize_t i, j;
+  struct sfnt_fedge edge;
+
+  for (i = 1; i < size; ++i)
+    {
+      edge = edges[i];
+      j = i - 1;
+
+      /* Comparing truncated values yields a faint speedup, for not as
+        many edges must be moved as would be otherwise.  */
+      while (j >= 0 && ((int) edges[j].bottom
+                       > (int) edge.bottom))
+       {
+         edges[j + 1] = edges[j];
+         j--;
+       }
+
+      edges[j + 1] = edge;
+    }
+}
+
+/* Draw EDGES, an unsorted array of polygon edges of size NEDGES.
+
+   Transform EDGES into an array of steps representing a raster with
+   HEIGHT scanlines, then call POLY_FUNC with DCONTEXT and the
+   resulting struct sfnt_step_raster to transfer it onto an actual
+   raster.
+
+   WIDTH must be the width of the raster.  Although there is no
+   guarantee that no steps generated extend past WIDTH, steps starting
+   after width might be omitted, and as such it must be accurate.  */
+
+static void
+sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges,
+                      size_t height, size_t width,
+                      sfnt_step_raster_proc proc, void *dcontext)
+{
+  int y;
+  size_t size, e;
+  struct sfnt_fedge *active, **prev, *a;
+  struct sfnt_step_raster raster;
+  struct sfnt_step_chunk *next, *last;
+
+  if (!height)
+    return;
+
+  /* Sort edges to ascend by Y-order.  Once again, remember: cartesian
+     coordinates.  */
+  sfnt_fedge_sort (edges, nedges);
+
+  /* Step down line by line.  Find active edges.  */
+
+  y = sfnt_floor_fixed (MAX (0, edges[0].bottom));
+  e = 0;
+  active = NULL;
+
+  /* Allocate the array of edges.  */
+
+  raster.scanlines = height;
+  raster.chunks    = NULL;
+
+  if (!INT_MULTIPLY_OK (height, sizeof *raster.steps, &size))
+    abort ();
+
+  raster.steps = xzalloc (size);
+
+  for (; y != height; y += 1)
+    {
+      /* Add in new edges keeping them sorted.  */
+      for (; e < nedges && edges[e].bottom < y + 1; ++e)
+       {
+         if (edges[e].top > y)
+           {
+             /* Find where to place this edge.  */
+             for (prev = &active; (a = *prev); prev = &(a->next))
+               {
+                 if (a->x > edges[e].x)
+                   break;
+               }
+
+             edges[e].next = *prev;
+             *prev = &edges[e];
+           }
+       }
+
+      /* Iterate through each active edge, appending steps for it, and
+        removing it if it does not overlap with the next
+        scanline.  */
+
+      for (prev = &active; (a = *prev);)
+       {
+         float x_top, x_bot, x_min, x_max;
+         float y_top, y_bot;
+         int x_pixel_min, x_pixel_max;
+
+#define APPEND_STEP(x, coverage)                               \
+         sfnt_insert_raster_step (&raster, x, coverage, y);
+
+         /* Calculate several values to establish which overlap
+            category this edge falls into.  */
+
+         y_top = y + 1; /* Topmost coordinate covered by this
+                           edge in this scanline.  */
+         y_bot = y;     /* Bottom-most coordinate covered by this
+                           edge in this scanline.  */
+
+         /* III or IV?  If the edge terminates before the next
+            scanline, make its terminus y_top.  */
+
+         if (y_top > a->top)
+           y_top = a->top;
+
+         /* Same goes for y_bottom.  */
+
+         if (a->bottom > y_bot)
+           y_bot = a->bottom;
+
+         /* y_top should never equal y_bottom, but check to be on the
+            safe side.  */
+         if (y_top == y_bot)
+           goto next;
+
+         /* x_top and x_bot are the X positions where the edge enters
+            and exits this scanline.  */
+
+         /*
+           (x_top)
+   +--------ee-----+------------------------------------------------+ (y_top)
+   |      ee.......|................................................|
+   |    ee.........|................................................|
+   |  ee...........|................................................|
+   |ee.............|................................................|
+  ee---------------+------------------------------------------------+ (y_bot)
+(x_bot)
+            (y_bot might be further below.)
+         */
+
+         x_top = (y_top - a->bottom) * a->step_x + a->x;
+         x_bot = (y_bot - a->bottom) * a->step_x + a->x;
+
+         x_min = MIN (x_top, x_bot);
+         x_max = MAX (x_top, x_bot);
+
+         /* Pixels containing x_bot and x_top respectively.  */
+         x_pixel_min = (int) (x_min);
+         x_pixel_max = (int) (x_max);
+
+#define TRAPEZOID_AREA(height, top_start, top_end, bot_start, bot_end) \
+         ((((float) (top_end) - (top_start))                           \
+           + ((float) (bot_end) - (bot_start)))                        \
+          / 2.0f * (float) (height))
+
+         /* I, III?  These two instances' criteria are that the edge
+            enters and exits within one pixel.  */
+
+         if (x_pixel_min == x_pixel_max)
+           {
+             float xmin, xmax, ytop, ybot, height;
+             float coverage, delta;
+
+             /* Partial coverage for the first pixel.  */
+
+             xmin = (x_min);
+             xmax = (x_max);
+             ytop = (y_top);
+             ybot = (y_bot);
+             height = ytop - ybot;
+
+             /* The trapezoid here is one of the following two:
+
+  ytop+------xmax--+-----------+---------------------------------------------+
+      |     /................................................................|
+      |    /.......|...........|.............................................|
+      |   /........|...........|.............................................|
+      |  /.........|...........|.............................................|
+      | / ...................................................................|
+  xmin+------------+-----------+---------------------------------------------+
+      ybot
+  ytop+------------+-----------+---------------------------------------------+
+      |\ xmin................................................................|
+      | \..........|...........|.............................................|
+      |  \.........|...........|.............................................|
+      |   \........|...........|.............................................|
+      |    \.......|...........|.............................................|
+      |     \................................................................|
+      +------xmax--+-----------+---------------------------------------------+
+
+                 In either situation, the first pixel's coverage is
+                 the space occupied by a trapezoid whose corners are
+                 xmin and x_pixel_min + 1 and xmax and x_pixel_min +
+                 1, and whose height is ytop - ybot.  The coverage for
+                 the remainder is the height alone.  */
+
+             coverage = (TRAPEZOID_AREA (height,
+                                         xmin, (int) xmin + 1,
+                                         xmax, (int) xmax + 1)
+                         * a->winding);
+             APPEND_STEP (x_pixel_min, coverage);
+
+             /* Then if the next pixel isn't beyond the raster,
+                append complete coverage for it.  */
+
+             if (x_pixel_min + 1 < width)
+               {
+                 delta = (y_top - y_bot) * a->winding;
+                 APPEND_STEP (x_pixel_max + 1, delta - coverage);
+               }
+           }
+         else
+           {
+             float dy, y_crossing, coverage;
+             float ytop, ybot, xtop, xbot, increment;
+             float x, last, here;
+
+             ytop = (y_top);
+             ybot = (y_bot);
+             xtop = (x_top);
+             xbot = (x_bot);
+
+#define TRIANGLE_AREA(width, height)                                   \
+             ((width) * (height) / 2.0f)
+
+             /* II, IV.  Coverage must be computed for each pixel
+                from x_pixel_min to x_pixel_max, with the latter
+                treated much as in I or III.  */
+
+             if (x_bot < x_top)
+               {
+                 /*
+
+
+  y_top                                                         x_top
+       
+-----------+-----------+-----------+------------+-------/------+-------------------------------+
+       |           |           |           |            |    
/--.......|...............................|
+       |x_pixel_min|           |           |            | 
/--..........|...............................|
+       |           |           |           |           
/+-y_crossing...|...............................|
+       |           |           |           |        
/--.|..............|...............................|
+       |           |           |           |      
/-....|..............|...............................|
+       |           |           |           |   
/--......|..x_pixel_max.|...............................|
+       |           |           |           
|/--.........|..............|...............................|
+       |           |           |         
/-+............|..............|...............................|
+       |           |           |      
/--..|............|..............|...............................|
+       |           |           |   
/--.....|............|..............|...............................|
+       |           |           
|/--........|............|..............|...............................|
+       |           |         
/-+...........|............|..............|...............................|
+       |           |      
/--..|...........|............|..............|...............................|
+       |           |   
/--.....|...........|............|..............|...............................|
+       |           | 
/-........|...........|............|..............|...............................|
+       |          
/+-y_crossing|...........|............|..............|...............................|
+       |       
/--.|...........|...........|............|..............|...............................|
+       |    
/--....|...........|...........|............|..............|...............................|
+       | 
/--.......|...........|...........|............|..............|...............................|
+       
+-----------+-----------+-----------+------------+--------------+-------------------------------+
+  y_bot x_bot
+
+
+The purpose of this code is to calculate the area occupied by dots of
+each pixel in between x_pixel_min and x_pixel_max + 1.
+
+The area occupied in the first pixel is a triangle comprising [x_bot,
+y_bot], [x_bot + 1, y_bot], and [x_bot + 1, y_crossing].
+
+The area occupied in the second pixel through x_pixel_max - 1 is that
+of a rectangle comprising [y_bot, pixel], [the previous rectangle's
+y_crossing, pixel], [the previous rectangle's y_crossing, pixel + 1],
+and [pixel + 1, y_bot] summed with the area the remaining triangle.
+
+The area occupied in the last pixel is a trapezoid proper.
+
+Thus the procedure is roughly as follows: dy is computed, which is the
+increase to the Y of the edge for each increase in scanline X.  */
+
+                 dy = a->step_y;
+
+                 /* As is y_crossing for the first pixel.  */
+                 y_crossing = ybot + dy * ((int) xbot + 1 - xbot);
+
+                 /* And the area of the first triangle.
+
+                    The width is (int) xbot + 1 - xbot, and the
+                    height is y_crossing - ybot.  */
+                 last = ((TRIANGLE_AREA (y_crossing - ybot,
+                                         (int) xbot + 1 - xbot))
+                         * a->winding);
+                 APPEND_STEP (x_pixel_min, last);
+
+                 /* Coverage value for subsequent rectangles.  The
+                    value set here is for the next pixel, which is
+                    filled from ybot to y_crossing.  */
+
+                 coverage = (y_crossing - ybot) * a->winding;
+                 increment = dy * a->winding;
+
+                 for (x = x_pixel_min + 1; x < x_pixel_max; x++)
+                   {
+                     here = coverage + increment / 2;
+                     APPEND_STEP (x, here - last);
+                     last = here;
+                     coverage += increment;
+                   }
+
+                 /* The y_crossing for the last pixel.  */
+                 y_crossing = ybot + dy * ((int) xtop - xbot);
+
+                 /* And calculate the area of the trapezoid in the
+                    last pixel.  */
+
+                 coverage += a->winding * TRAPEZOID_AREA (ytop - y_crossing,
+                                                          xtop,
+                                                          (int) xtop + 1,
+                                                          (int) xtop,
+                                                          (int) xtop + 1);
+                 here = coverage;
+                 APPEND_STEP (x_pixel_max, here - last);
+                 last = here;
+
+                 /* Fill the remainder of the scanline with
+                    height-derived coverage.  */
+
+                 if (x_pixel_max + 1 < width)
+                   APPEND_STEP (x_pixel_max + 1, ((y_top - y_bot)
+                                                  * a->winding - last));
+               }
+             else /* if (x_bot > x_top) */
+               {
+                 /*
+
+  y_top   x_top
+    
+----------------+----------------+-----------------+-----------------+-----------------------------+
+    |     
\--........|................|.................|.................|.............................|
+    |        
\--.....|................|.................|.................|.............................|
+    |           
\--..|................|.................|.................|.............................|
+    |              
\-+.y_crossing.....|.................|.................|.............................|
+    |                
|\--.............|.................|.................|.............................|
+    |                |   
\--..........|.................|.................|.............................|
+    |  x_pixel_min   |      
\---......|.................|.................|.............................|
+    |                |          
\--...|.................|.................|.............................|
+    |                |             
\--|y_crossing.......|.................|.............................|
+    |                |                
\--...............|.................|.............................|
+    |                |                |  
\--............|.................|.............................|
+    |                |                |     
\--.........|.................|.............................|
+    |                |                |        
\--......|.................|.............................|
+    
+----------------+----------------+-----------\-----+-----------------+-----------------------------+
+  y_bot                                        x_bot
+
+Whereas in this situation the trapezoid is inverted, and the code must
+be as well.  */
+
+                 /* The edge's Y decreases as the edge's X increases,
+                    yielding a negative a->step_x.  */
+                 dy = a->step_y;
+
+                 /* Calculate y_crossing for the first pixel.  */
+                 y_crossing = ytop + dy * ((int) xtop + 1 - xtop);
+
+                 /* And the area of the first triangle.  */
+                 last = ((TRIANGLE_AREA ((int) xtop + 1 - xtop,
+                                         ytop - y_crossing))
+                         * a->winding);
+                 APPEND_STEP (x_pixel_min, last);
+
+                 /* Coverage value for subsequent rectangles.  The
+                    value set here is for the next pixel, which is
+                    filled from ytop to y_crossing.  */
+                 coverage = (ytop - y_crossing) * a->winding;
+                 increment = -dy * a->winding;
+
+                 for (x = x_pixel_min + 1; x < x_pixel_max; x ++)
+                   {
+                     here = coverage + increment / 2;
+                     APPEND_STEP (x, here - last);
+                     last = here;
+                     coverage += increment;
+                   }
+
+                 /* The y_crossing for the last pixel.  */
+                 y_crossing = ytop + dy * ((int) xbot - xtop);
+
+                 /* And calculate the area of the trapezoid in the
+                    last pixel.  */
+
+                 coverage += a->winding * TRAPEZOID_AREA (y_crossing - ybot,
+                                                          (int) xbot,
+                                                          (int) xbot + 1,
+                                                          xbot,
+                                                          (int) xbot + 1);
+                 here = coverage;
+                 APPEND_STEP (x_pixel_max, here - last);
+                 last = here;
+
+                 /* Fill the remainder of the scanline with
+                    height-derived coverage.  */
+
+                 if (x_pixel_max + 1 < width)
+                   APPEND_STEP (x_pixel_max + 1, ((y_top - y_bot)
+                                                  * a->winding - last));
+               }
+
+#undef TRIANGLE_AREA
+           }
+
+#undef APPEND_STEP
+#undef TRAPEZOID_AREA
+
+         /* When an edge is created, its a->bottom (and by extension
+            a->y) is not aligned to a->x.  Since this iteration can
+            only affect the scan line Y, align a to the next
+            scanline, that the next iteration of this loop to
+            consider it might consider its entire intersection.  */
+         a->x += a->step_x * (y + 1 - a->bottom);
+         a->bottom = y + 1;
+       next:
+
+         if (a->top < y + 1)
+           *prev = a->next;
+         else
+           prev = &a->next;
+       }
+
+      /* Break if all is done.  */
+      if (!active && e == nedges)
+       break;
+    }
+
+  (*proc) (&raster, dcontext);
+  xfree (raster.steps);
+
+  /* Free each block of steps allocated.  */
+  next = raster.chunks;
+  while (next)
+    {
+      last = next;
+      next = next->next;
+      xfree (last);
+    }
+
+#undef ONE_PIXEL
+}
+
+/* Apply winding rule to the coverage value VALUE.  Convert VALUE to a
+   number between 0 and 255.  If VALUE is negative, invert it.  If it
+   exceeds 255 afterwards, truncate it to 255.  */
+
+static int
+sfnt_compute_fill (float value)
+{
+  if (value < 0)
+    value = -value;
+
+  return MIN (value * 255, 255);
+}
+
+/* Set N pixels at DATA to the value VALUE.  If N is large, call
+   memset; otherwise set this by hand.  */
+
+static void
+sfnt_poly_set_steps (unsigned char *data, int value, int n)
+{
+  unsigned char *p;
+
+  p = data;
+  switch (n)
+    {
+    case 7:
+      *p++ = value;
+      FALLTHROUGH;
+    case 6:
+      *p++ = value;
+      FALLTHROUGH;
+    case 5:
+      *p++ = value;
+      FALLTHROUGH;
+    case 4:
+      *p++ = value;
+      FALLTHROUGH;
+    case 3:
+      *p++ = value;
+      FALLTHROUGH;
+    case 2:
+      *p++ = value;
+      FALLTHROUGH;
+    case 1:
+      *p++ = value;
+      FALLTHROUGH;
+    case 0:
+      break;
+    default:
+      memset (data, value, n);
+    }
+}
+
+/* Transfer steps generated by sfnt_poly_edges_exact from STEPS to the
+   provided raster RASTER.  */
+
+static void
+sfnt_poly_steps (struct sfnt_step_raster *steps,
+                struct sfnt_raster *raster)
+{
+  int y;
+  unsigned char *data;
+  int x, xend, fill;
+  float total;
+  struct sfnt_step *step;
+
+  y = 0; /* This y is an X-style coordinate in RASTER's space.
+
+           Its counterpart array of steps is STEPS->steps[
+           raster->height - y - 1].  */
+  data = raster->cells;
+
+  for (y = 0; y < raster->height; ++y, data += raster->stride)
+    {
+      fill = total = x = 0;
+
+      for (step = steps->steps[raster->height - y - 1];
+          step && x < raster->width; step = step->next)
+       {
+         xend = MIN (step->x, raster->width);
+
+         if (fill)
+           sfnt_poly_set_steps (data + x, fill, xend - x);
+
+         total += step->coverage;
+         fill = sfnt_compute_fill (total);
+         x = xend;
+       }
+
+      if (x < raster->width)
+        sfnt_poly_set_steps (data + x, fill, raster->width - x);
+    }
+}
+
+/* Poly each edge in EDGES onto the raster supplied in DCONTEXT.  */
+
+static void
+sfnt_raster_steps (struct sfnt_step_raster *steps, void *dcontext)
+{
+  sfnt_poly_steps (steps, dcontext);
+}
+
+/* Call sfnt_poly_edges_exact with suitable arguments for polying
+   EDGES onto DCONTEXT, a raster structure.  */
+
+static void
+sfnt_raster_edges_exact (struct sfnt_fedge *edges, size_t size,
+                        void *dcontext)
+{
+  struct sfnt_raster *raster;
+
+  raster = dcontext;
+  sfnt_poly_edges_exact (edges, size, raster->height,
+                        raster->width, sfnt_raster_steps,
+                        dcontext);
+}
+
+/* Generate an alpha mask for the glyph outline OUTLINE by means of
+   the exact coverage scaler.  Value is the alpha mask upon success,
+   NULL upon failure.  */
+
+TEST_STATIC struct sfnt_raster *
+sfnt_raster_glyph_outline_exact (struct sfnt_glyph_outline *outline)
+{
+  struct sfnt_raster raster, *data;
+
+  /* Get the raster parameters.  */
+  sfnt_prepare_raster (&raster, outline);
+
+  /* Allocate the raster data.  */
+  data = xmalloc (sizeof *data + raster.stride * raster.height);
+  *data = raster;
+  data->cells = (unsigned char *) (data + 1);
+  memset (data->cells, 0, raster.stride * raster.height);
+
+  /* Generate edges for the outline, polying each array of edges to
+     the raster.  */
+  sfnt_build_outline_fedges (outline, sfnt_raster_edges_exact, data);
+
+  /* All done.  */
+  return data;
+}
+
+
+
 /* Glyph metrics computation.  */
 
 /* Read an hmtx table from the font FD, using the table directory
@@ -4756,7 +5697,7 @@ sfnt_get_scale (struct sfnt_head_table *head, int ppem)
   /* Figure out how to convert from font unit-space to pixel space.
      To turn one unit to its corresponding pixel size given a ppem of
      1, the unit must be divided by head->units_per_em.  Then, it must
-     be multipled by the ppem.  So,
+     be multiplied by the ppem.  So,
 
        PIXEL = UNIT / UPEM * PPEM
 
@@ -4896,7 +5837,7 @@ sfnt_read_name_table (int fd, struct sfnt_offset_subtable 
*subtable)
       return NULL;
     }
 
-  /* Read REQURIED bytes into the string data.  */
+  /* Read REQUIRED bytes into the string data.  */
   name->data = (unsigned char *) (name->name_records
                                  + name->count);
   rc = read (fd, name->data, required);
@@ -5854,15 +6795,6 @@ sfnt_interpret_trap (struct sfnt_interpreter 
*interpreter,
     TRAP ("instruction executed not valid"     \
          " outside control value program")     \
 
-#define sfnt_add(a, b)                         \
-  ((int) ((unsigned int) (a) + (unsigned int) (b)))
-
-#define sfnt_sub(a, b)                         \
-  ((int) ((unsigned int) (a) - (unsigned int) (b)))
-
-#define sfnt_mul(a, b)                         \
-  ((int) ((unsigned int) (a) * (unsigned int) (b)))
-
 
 
 /* Register, alu and logic instructions.  */
@@ -5897,7 +6829,7 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
    ? (TRAP ("stack underflow"), 0)             \
    : *(interpreter->SP - 1))
 
-#if !defined TEST || !0
+#if !defined TEST
 
 #define PUSH(value)                            \
   {                                            \
@@ -5915,7 +6847,7 @@ sfnt_interpret_trap (struct sfnt_interpreter *interpreter,
     interpreter->SP++;                         \
   }
 
-#else /* TEST && 0 */
+#else /* TEST */
 
 #define PUSH(value)                            \
   {                                            \
@@ -7444,6 +8376,8 @@ static void
 sfnt_interpret_utp (struct sfnt_interpreter *interpreter,
                    uint32_t p)
 {
+  unsigned char mask;
+
   if (!interpreter->state.zp0)
     {
       if (p >= interpreter->twilight_zone_size)
@@ -7457,7 +8391,31 @@ sfnt_interpret_utp (struct sfnt_interpreter *interpreter,
       || p >= interpreter->glyph_zone->num_points)
     TRAP ("UTP[] p lies outside glyph zone");
 
-  interpreter->glyph_zone->flags[p] &= ~SFNT_POINT_TOUCHED_X;
+  /* The flags unset by UTP are subject to which axes in the freedom
+     vector are significant, as stated in the TrueType reference
+     manual by this needless mouthful:
+
+       A point may be touched in the x-direction, the y-direction, or
+       in both the x and y-directions.  The position of the freedom
+       vector determines whether the point is untouched in the
+       x-direction, the y-direction, or both.  If the vector is set to
+       the x-axis, the point will be untouched in the x-direction.  If
+       the vector is set to the y-axis, the point will be untouched in
+       the y-direction.  Otherwise the point will be untouched in both
+       directions.
+
+       A points that is marked as untouched will be moved by an IUP[]
+       instruction even if the point was previously touched.  */
+
+  mask = 0xff;
+
+  if (interpreter->state.freedom_vector.x)
+    mask &= ~SFNT_POINT_TOUCHED_X;
+
+  if (interpreter->state.freedom_vector.y)
+    mask &= ~SFNT_POINT_TOUCHED_Y;
+
+  interpreter->glyph_zone->flags[p] &= mask;
 }
 
 /* Save the specified unit VECTOR into INTERPRETER's graphics state as
@@ -8798,7 +9756,7 @@ sfnt_deltac (int number, struct sfnt_interpreter 
*interpreter,
 
    Touch the point P (within the zone specified in zp0) in the
    directions specified in the freedom vector.  Then, if OPCODE is
-   0x7f, round the point and move it the rounded distance along the
+   0x2f, round the point and move it the rounded distance along the
    freedom vector.
 
    Finally, set the RP0 and RP1 registers to P.  */
@@ -8814,7 +9772,7 @@ sfnt_interpret_mdap (struct sfnt_interpreter *interpreter,
   /* Measure the current distance.  */
   here = sfnt_project_vector (interpreter, px, py);
 
-  if (opcode == 0x7f)
+  if (opcode == 0x2f)
     {
       /* Measure distance, round, then move to the distance.  */
       distance = sfnt_project_vector (interpreter, px, py);
@@ -8841,12 +9799,10 @@ sfnt_interpret_mdap (struct sfnt_interpreter 
*interpreter,
 
 static void
 sfnt_deltap (int number, struct sfnt_interpreter *interpreter,
-            unsigned char operand, unsigned int index)
+            unsigned char operand, unsigned int p)
 {
   int ppem, delta;
 
-  return;
-
   /* Extract the ppem from OPERAND.  The format is the same as in
      sfnt_deltac.  */
 
@@ -8950,8 +9906,8 @@ sfnt_deltap (int number, struct sfnt_interpreter 
*interpreter,
   delta *= 1l << (6 - interpreter->state.delta_shift);
 
   /* Move the point.  */
-  sfnt_check_zp0 (interpreter, index);
-  sfnt_move_zp0 (interpreter, index, 1, delta);
+  sfnt_check_zp0 (interpreter, p);
+  sfnt_move_zp0 (interpreter, p, 1, delta);
 }
 
 /* Needed by sfnt_interpret_call.  */
@@ -10375,8 +11331,8 @@ sfnt_interpret_mdrp (struct sfnt_interpreter 
*interpreter,
                     uint32_t opcode)
 {
   uint32_t p;
-  sfnt_f26dot6 distance, delta;
-  sfnt_f26dot6 current_projection, original_projection;
+  sfnt_f26dot6 distance, applied;
+  sfnt_f26dot6 current_projection;
   sfnt_f26dot6 x, y, org_x, org_y;
   sfnt_f26dot6 rx, ry, org_rx, org_ry;
 
@@ -10388,20 +11344,21 @@ sfnt_interpret_mdrp (struct sfnt_interpreter 
*interpreter,
   sfnt_address_zp0 (interpreter, interpreter->state.rp0,
                    &rx, &ry, &org_rx, &org_ry);
 
+  /* Calculate the distance between P and rp0 prior to hinting.  */
   distance = DUAL_PROJECT (org_x - org_rx,
                           org_y - org_ry);
-  original_projection = distance;
+
+  /* Calculate the distance between P and rp0 as of now in the hinting
+     process.  */
   current_projection = PROJECT (x - rx, y - ry);
 
   /* Test against the single width value.  */
 
-  delta = sfnt_sub (distance,
-                   interpreter->state.single_width_value);
-
-  if (delta < 0)
-    delta = -delta;
-
-  if (delta < interpreter->state.sw_cut_in)
+  if (interpreter->state.sw_cut_in > 0
+      && distance < (interpreter->state.single_width_value
+                    + interpreter->state.sw_cut_in)
+      && distance > (interpreter->state.single_width_value
+                    - interpreter->state.sw_cut_in))
     {
       /* Use the single width instead, as the CVT entry is too
         small.  */
@@ -10412,38 +11369,34 @@ sfnt_interpret_mdrp (struct sfnt_interpreter 
*interpreter,
        distance = -interpreter->state.single_width_value;
     }
 
-  /* Flag B means look at the cvt cut in and round the
-     distance.  */
+  /* Flag B implies that the distance should be rounded.  The CVT cut
+     in is not taken into account by MDRP, contrary to earlier
+     presumptions.  */
 
   if (opcode & 4)
-    {
-      delta = sfnt_sub (distance, original_projection);
-
-      if (delta < 0)
-       delta = -delta;
-
-      if (delta > interpreter->state.cvt_cut_in)
-       distance = original_projection;
-
-      /* Now, round the distance.  */
-      distance = sfnt_round_symmetric (interpreter, distance);
-    }
+    applied = sfnt_round_symmetric (interpreter, distance);
+  else
+    applied = distance;
 
   /* Flag C means look at the minimum distance.  */
 
   if (opcode & 8)
     {
-      if (original_projection >= 0
-         && distance < interpreter->state.minimum_distance)
-       distance = interpreter->state.minimum_distance;
-      else if (original_projection < 0
-              && distance > -interpreter->state.minimum_distance)
-       distance = -interpreter->state.minimum_distance;
+      /* Test the sign of the initial distance, but compare the
+        distance that will be applied in reality against the minimum
+        distance.  */
+
+      if (distance >= 0
+         && applied < interpreter->state.minimum_distance)
+       applied = interpreter->state.minimum_distance;
+      else if (distance < 0
+              && applied > -interpreter->state.minimum_distance)
+       applied = -interpreter->state.minimum_distance;
     }
 
   /* Finally, move the point.  */
   sfnt_move_zp1 (interpreter, p, 1,
-                sfnt_sub (distance, current_projection));
+                sfnt_sub (applied, current_projection));
 
   /* Set RP1 to RP0 and RP2 to the point.  If flag 3 is set, also make
      it RP0.  */
@@ -11284,6 +12237,7 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph,
                             sfnt_f26dot6 *x2, sfnt_f26dot6 *y2)
 {
   sfnt_fword f1, f2;
+  sfnt_fixed s1, s2;
 
   /* Two ``phantom points'' are appended to each outline by the scaler
      prior to instruction interpretation.  One of these points
@@ -11301,8 +12255,14 @@ sfnt_compute_phantom_points (struct sfnt_glyph *glyph,
   f2 += glyph->advance_distortion;
 
   /* Next, scale both up.  */
-  *x1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale);
-  *x2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale);
+  s1 = sfnt_mul_f26dot6_fixed (f1 * 64, scale);
+  s2 = sfnt_mul_f26dot6_fixed (f2 * 64, scale);
+
+  /* While not expressly provided in the manual, the phantom points
+     (at times termed the advance and origin points) represent pixel
+     coordinates within the raster, and are therefore rounded.  */
+  *x1 = sfnt_round_f26dot6 (s1);
+  *x2 = sfnt_round_f26dot6 (s2);
 
   /* Clear y1 and y2.  */
   *y1 = 0;
@@ -11425,8 +12385,8 @@ sfnt_interpret_simple_glyph (struct sfnt_glyph *glyph,
   /* Load phantom points.  */
   zone->y_points[i] = phantom_point_1_y;
   zone->y_points[i + 1] = phantom_point_2_y;
-  zone->y_current[i] = phantom_point_1_x;
-  zone->y_current[i + 1] = phantom_point_2_x;
+  zone->y_current[i] = phantom_point_1_y;
+  zone->y_current[i + 1] = phantom_point_2_y;
 
   /* Load phantom point flags.  */
   zone->flags[i] = SFNT_POINT_PHANTOM;
@@ -11877,7 +12837,7 @@ sfnt_interpret_compound_glyph_1 (struct sfnt_glyph 
*glyph,
       else
        {
          /* The offset is determined by matching a point location in
-            a preceeding component with a point location in the
+            a preceding component with a point location in the
             current component.  The index of the point in the
             previous component is established by adding
             component->argument1.a or component->argument1.c to
@@ -14253,7 +15213,7 @@ sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t 
start,
            }
          else
            {
-             /* ... otheriwse, move point j by the delta of the
+             /* ... otherwise, move point j by the delta of the
                 nearest touched point.  */
 
              if (x[j] >= max_pos)
@@ -14317,7 +15277,7 @@ sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t 
start,
            }
          else
            {
-             /* ... otheriwse, move point j by the delta of the
+             /* ... otherwise, move point j by the delta of the
                 nearest touched point.  */
 
              if (y[j] >= max_pos)
@@ -14401,7 +15361,7 @@ sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t 
start,
            }
          else
            {
-             /* ... otheriwse, move point j by the delta of the
+             /* ... otherwise, move point j by the delta of the
                 nearest touched point.  */
 
              if (x[j] >= max_pos)
@@ -14465,7 +15425,7 @@ sfnt_infer_deltas_1 (struct sfnt_glyph *glyph, size_t 
start,
            }
          else
            {
-             /* ... otheriwse, move point j by the delta of the
+             /* ... otherwise, move point j by the delta of the
                 nearest touched point.  */
 
              if (y[j] >= max_pos)
@@ -14554,7 +15514,7 @@ sfnt_infer_deltas (struct sfnt_glyph *glyph, bool 
*touched,
    of one or two coordinates for each axis.  Each such list is
    referred to as a ``tuple''.
 
-   The deltas, one for each point, are multipled by the normalized
+   The deltas, one for each point, are multiplied by the normalized
    value of each axis and applied to those points for each tuple that
    is found to be applicable.
 
@@ -15934,7 +16894,7 @@ sfnt_x_raster (struct sfnt_raster **rasters,
          ascent = sfnt_mul_fixed (hhea->ascent * 65536,
                                   scale) / 65536;
 
-         origin = 0;
+         origin = 5;
 
          for (i = 0; i < nrasters; ++i)
            {
@@ -19196,6 +20156,11 @@ sfnt_identify_instruction (struct sfnt_interpreter 
*interpreter)
   return buffer;
 }
 
+/* Function called to rasterize a glyph outline.  */
+#define TYPE struct sfnt_glyph_outline *
+static struct sfnt_raster *(*test_raster_glyph_outline) (TYPE);
+#undef TYPE
+
 static void
 sfnt_verbose (struct sfnt_interpreter *interpreter)
 {
@@ -19229,7 +20194,7 @@ sfnt_verbose (struct sfnt_interpreter *interpreter)
              sfnt_coerce_fixed (outline->xmax),
              sfnt_coerce_fixed (outline->ymax));
 
-      raster = sfnt_raster_glyph_outline (outline);
+      raster = (*test_raster_glyph_outline) (outline);
 
       if (raster)
        sfnt_test_raster (raster, NULL, 0);
@@ -19452,6 +20417,11 @@ main (int argc, char **argv)
       exit (0);
     }
 
+  if (getenv ("SFNT_EXACT_SCALING"))
+    test_raster_glyph_outline = sfnt_raster_glyph_outline_exact;
+  else
+    test_raster_glyph_outline = sfnt_raster_glyph_outline;
+
   fd = open (argv[1], O_RDONLY);
 
   if (fd < 0)
@@ -19543,8 +20513,8 @@ main (int argc, char **argv)
       return 1;
     }
 
-#define FANCY_PPEM 18
-#define EASY_PPEM  18
+#define FANCY_PPEM 14
+#define EASY_PPEM  14
 
   interpreter = NULL;
   head = sfnt_read_head_table (fd, font);
@@ -19795,7 +20765,7 @@ main (int argc, char **argv)
 
          xfree (value);
 
-         raster = sfnt_raster_glyph_outline (outline);
+         raster = (*test_raster_glyph_outline) (outline);
 
          if (!raster)
            exit (7);
@@ -20100,10 +21070,10 @@ main (int argc, char **argv)
 
                  clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
 
-                 for (i = 0; i < 120; ++i)
+                 for (i = 0; i < 800; ++i)
                    {
                      xfree (raster);
-                     raster = sfnt_raster_glyph_outline (outline);
+                     raster = (*test_raster_glyph_outline) (outline);
                    }
 
                  clock_gettime (CLOCK_THREAD_CPUTIME_ID, &end);
@@ -20188,7 +21158,8 @@ main (int argc, char **argv)
 
                              if (outline)
                                {
-                                 raster = sfnt_raster_glyph_outline (outline);
+                                 raster
+                                   = (*test_raster_glyph_outline) (outline);
 
                                  if (raster)
                                    {
@@ -20214,7 +21185,7 @@ main (int argc, char **argv)
              printf ("time spent building edges: %lld sec %ld nsec\n",
                      (long long) sub1.tv_sec, sub1.tv_nsec);
              printf ("time spent rasterizing: %lld sec %ld nsec\n",
-                     (long long) sub2.tv_sec / 120, sub2.tv_nsec / 120);
+                     (long long) sub2.tv_sec / 800, sub2.tv_nsec / 800);
 
              xfree (outline);
            }
diff --git a/src/sfnt.h b/src/sfnt.h
index f6ab6a6eebd..2ae47ad30ce 100644
--- a/src/sfnt.h
+++ b/src/sfnt.h
@@ -123,6 +123,7 @@ typedef int16_t sfnt_fword;
 typedef uint16_t sfnt_ufword;
 
 #define sfnt_coerce_fixed(fixed) ((sfnt_fixed) (fixed) / 65535.0)
+#define sfnt_fixed_float(fixed)  ((sfnt_fixed) (fixed) / 65535.0f)
 
 typedef unsigned int sfnt_glyph;
 typedef unsigned int sfnt_char;
@@ -778,7 +779,7 @@ struct sfnt_edge
   /* X position, top and bottom of edges.  */
   sfnt_fixed x, top, bottom;
 
-  /* Amount to move X by upon each change of Y.  */
+  /* Amount to move X by upon each change of Y, and vice versa.  */
   sfnt_fixed step_x;
 };
 
@@ -1283,7 +1284,7 @@ struct sfnt_gvar_table
   unsigned char *glyph_variation_data;
 };
 
-/* Structure repesenting a set of axis coordinates and their
+/* Structure representing a set of axis coordinates and their
    normalized equivalents.
 
    To use this structure, call
@@ -1511,6 +1512,7 @@ extern void sfnt_prepare_raster (struct sfnt_raster *,
 
 #define PROTOTYPE struct sfnt_glyph_outline *
 extern struct sfnt_raster *sfnt_raster_glyph_outline (PROTOTYPE);
+extern struct sfnt_raster *sfnt_raster_glyph_outline_exact (PROTOTYPE);
 #undef PROTOTYPE
 
 #define PROTOTYPE                      \
diff --git a/src/sfntfont.c b/src/sfntfont.c
index 68e850779fc..0a8797bfb3b 100644
--- a/src/sfntfont.c
+++ b/src/sfntfont.c
@@ -1348,7 +1348,7 @@ sfntfont_charset_for_cmap (struct 
sfnt_cmap_encoding_subtable subtable)
    subtable in *SUBTABLE upon success, NULL otherwise.
 
    If FORMAT14 is non-NULL, return any associated format 14 variation
-   selection context in *FORMAT14 should the selected charcter map be
+   selection context in *FORMAT14 should the selected character map be
    a Unicode character map.  */
 
 static struct sfnt_cmap_encoding_subtable_data *
@@ -1371,7 +1371,7 @@ sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
          if (!format14)
            return data[i];
 
-         /* Search for a correspoinding format 14 character map.
+         /* Search for a corresponding format 14 character map.
             This is used in conjunction with the selected character
             map to map variation sequences.  */
 
@@ -1400,7 +1400,7 @@ sfntfont_select_cmap (struct sfnt_cmap_table *cmap,
          if (!format14)
            return data[i];
 
-         /* Search for a correspoinding format 14 character map.
+         /* Search for a corresponding format 14 character map.
             This is used in conjunction with the selected character
             map to map variation sequences.  */
 
@@ -2444,7 +2444,11 @@ sfntfont_get_glyph_raster (sfnt_glyph glyph_code,
     }
 
   /* Not already cached.  Raster the outline.  */
-  raster = sfnt_raster_glyph_outline (outline);
+
+  if (!sfnt_raster_glyphs_exactly)
+    raster = sfnt_raster_glyph_outline (outline);
+  else
+    raster = sfnt_raster_glyph_outline_exact (outline);
 
   if (!raster)
     return NULL;
@@ -4116,6 +4120,13 @@ eliminating artifacts and chance effects consequent upon 
the direct
 upscaling of glyph outline data.  Instruction code is occasionally
 incompatible with Emacs and must be disregarded.  */);
   Vsfnt_uninstructable_family_regexp = Qnil;
+
+  DEFVAR_BOOL ("sfnt-raster-glyphs-exactly", sfnt_raster_glyphs_exactly,
+    doc: /* How font glyph outlines should be converted to graphics.
+If non-nil, glyphs will be displayed in a more precise manner, at the
+cost of performance on devices where floating-point math operations
+are slow.  */);
+  sfnt_raster_glyphs_exactly = true;
 }
 
 void
diff --git a/src/textconv.c b/src/textconv.c
index bd72562317f..fb1c66bb2c2 100644
--- a/src/textconv.c
+++ b/src/textconv.c
@@ -23,7 +23,7 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
    They may then request that the text editor remove or substitute
    that text for something else, for example when providing the
    ability to ``undo'' or ``edit'' previously composed text.  This is
-   most commonly seen in input methods for CJK laguages for X Windows,
+   most commonly seen in input methods for CJK languages for X Windows,
    and is extensively used throughout Android by input methods for all
    kinds of scripts.
 
@@ -1311,7 +1311,7 @@ struct complete_edit_check_context
 
 /* Convert PTR to CONTEXT.  If CONTEXT->check is false, then update
    CONTEXT->w's ephemeral last point and give it to the input method,
-   the assumption being that an editing operation signalled.  */
+   the assumption being that an editing operation signaled.  */
 
 static void
 complete_edit_check (void *ptr)
@@ -1379,7 +1379,7 @@ handle_pending_conversion_events_1 (struct frame *f,
      or not the editing operation completed successfully.  */
   context.check = false;
 
-  /* Make sure completion is signalled.  */
+  /* Make sure completion is signaled.  */
   count = SPECPDL_INDEX ();
   record_unwind_protect_ptr (complete_edit, &token);
   w = NULL;
diff --git a/src/tparam.c b/src/tparam.c
index a0d2ee74d99..84a063e9307 100644
--- a/src/tparam.c
+++ b/src/tparam.c
@@ -183,7 +183,7 @@ tparam1 (const char *string, char *outstring, int len,
              argp++;
              break;
 
-           case 'b':           /* %b means back up one arg (and re-use it).  */
+           case 'b':           /* %b means back up one arg (and reuse it).  */
              argp--;
              break;
 
diff --git a/src/treesit.c b/src/treesit.c
index 896ec05ee9f..f736415ebf9 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -2063,9 +2063,8 @@ DEFUN ("treesit-node-field-name-for-child",
 Return nil if there's no Nth child, or if it has no field.
 If NODE is nil, return nil.
 
-N counts all children, i.e., named ones and anonymous ones.
-
-N could be negative, e.g., -1 represents the last child.  */)
+Note that N counts named nodes only.  Also, N could be negative, e.g.,
+-1 represents the last child.  */)
   (Lisp_Object node, Lisp_Object n)
 {
   if (NILP (node))
@@ -2079,7 +2078,7 @@ N could be negative, e.g., -1 represents the last child.  
*/)
 
   /* Process negative index.  */
   if (idx < 0)
-    idx = ts_node_child_count (treesit_node) + idx;
+    idx = ts_node_named_child_count (treesit_node) + idx;
   if (idx < 0)
     return Qnil;
   if (idx > UINT32_MAX)
@@ -3286,7 +3285,7 @@ treesit_traverse_get_predicate (Lisp_Object thing, 
Lisp_Object language)
    there's an error, set SIGNAL_DATA to (ERR . DATA), where ERR is an
    error symbol, and DATA is something signal accepts, and return
    false, otherwise return true.  This function also check for
-   recusion levels: we place a arbitrary 100 level limit on recursive
+   recursion 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.  */
@@ -3335,7 +3334,7 @@ treesit_traverse_validate_predicate (Lisp_Object pred,
          if (!CONSP (cdr))
            {
              *signal_data = list3 (Qtreesit_invalid_predicate,
-                                   build_string ("Invalide `not' "
+                                   build_string ("Invalid `not' "
                                                  "predicate"),
                                    pred);
              return false;
diff --git a/src/window.c b/src/window.c
index e802ffb3fe2..3d18d48bfb7 100644
--- a/src/window.c
+++ b/src/window.c
@@ -526,7 +526,7 @@ select_window (Lisp_Object window, Lisp_Object norecord,
     /* Do not select a tooltip window (Bug#47207).  */
     error ("Cannot select a tooltip window");
 
-  /* We deinitely want to select WINDOW, not the mini-window.  */
+  /* We definitely want to select WINDOW, not the mini-window.  */
   f->select_mini_window_flag = false;
 
   /* Make the selected window's buffer current.  */
diff --git a/src/window.h b/src/window.h
index 9ef8434af18..346dc70ea98 100644
--- a/src/window.h
+++ b/src/window.h
@@ -292,7 +292,7 @@ struct window
 
        `last_point' is normally used during redisplay to indicate the
        position of point as seem by the input method.  However, it is
-       not updated if consequtive conversions are processed at the
+       not updated if consecutive conversions are processed at the
        same time.
 
        This `ephemeral_last_point' field is either the last point as
diff --git a/src/xdisp.c b/src/xdisp.c
index d123e273643..b46259ebf89 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -11437,7 +11437,7 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object 
from, Lisp_Object to,
       /* Start at the beginning of the line containing FROM.  Otherwise
         IT.current_x will be incorrectly set to zero at some arbitrary
         non-zero X coordinate.  */
-      reseat_at_previous_visible_line_start (&it);
+      move_it_by_lines (&it, 0);
       it.current_x = it.hpos = 0;
       if (IT_CHARPOS (it) != start)
        {
@@ -11514,6 +11514,8 @@ window_text_pixel_size (Lisp_Object window, Lisp_Object 
from, Lisp_Object to,
      the width of the last buffer position manually.  */
   if (IT_CHARPOS (it) > end)
     {
+      int end_y = it.current_y;
+
       end--;
       RESTORE_IT (&it, &it2, it2data);
       x = move_it_to (&it, end, to_x, max_y, -1, move_op);
@@ -11526,14 +11528,29 @@ window_text_pixel_size (Lisp_Object window, 
Lisp_Object from, Lisp_Object to,
 
          /* DTRT if ignore_line_at_end is t.  */
          if (!NILP (ignore_line_at_end))
-           doff = (max (it.max_ascent, it.ascent)
-                   + max (it.max_descent, it.descent));
+           {
+             /* If END-1 is on the previous screen line, we need to
+                 account for the vertical dimensions of previous line.  */
+             if (it.current_y < end_y)
+               doff = (max (it.max_ascent, it.ascent)
+                       + max (it.max_descent, it.descent));
+           }
          else
            {
              it.max_ascent = max (it.max_ascent, it.ascent);
              it.max_descent = max (it.max_descent, it.descent);
            }
        }
+      else if (IT_CHARPOS (it) > end
+              && it.line_wrap == TRUNCATE
+              && it.current_x - it.first_visible_x >= it.last_visible_x)
+       {
+          /* If the display property at END is at the beginning of the
+             line, and the previous line was truncated, we are at END,
+             but it.current_y is not yet updated to reflect that.  */
+          it.current_y += max (it.max_ascent, it.ascent)
+                          + max (it.max_descent, it.descent);
+       }
     }
   else
     bidi_unshelve_cache (it2data, true);
@@ -31344,9 +31361,16 @@ produce_image_glyph (struct it *it)
 
   take_vertical_position_into_account (it);
 
-  /* Automatically crop wide image glyphs at right edge so we can
-     draw the cursor on same display row.  */
-  if ((crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0)
+  /* Automatically crop wide image glyphs at right edge so we can draw
+     the cursor on same display row.  But don't do that under
+     word-wrap, unless the image starts at column zero, because
+     wrapping correctly needs the real pixel width of the image.  */
+  if ((it->line_wrap != WORD_WRAP
+       || it->hpos == 0
+       /* Always crop images larger than the window-width, minus 1 space.  */
+       || it->pixel_width > it->last_visible_x - FRAME_COLUMN_WIDTH (it->f))
+      && (crop = it->pixel_width - (it->last_visible_x - it->current_x),
+         crop > 0)
       && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
     {
       it->pixel_width -= crop;
diff --git a/src/xfont.c b/src/xfont.c
index ce32c7a2188..fdadb05500a 100644
--- a/src/xfont.c
+++ b/src/xfont.c
@@ -238,7 +238,7 @@ xfont_chars_supported (Lisp_Object chars, XFontStruct 
*xfont,
 
 static Lisp_Object xfont_scripts_cache;
 
-/* Re-usable vector to store characteristic font properties.   */
+/* Reusable vector to store characteristic font properties.   */
 static Lisp_Object xfont_scratch_props;
 
 /* Return a list of scripts supported by the font of FONTNAME whose
diff --git a/src/xselect.c b/src/xselect.c
index c38a1f8b6a9..5ffa0fd24fc 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -897,7 +897,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, 
Window requestor,
 
       /* Find a valid (non-zero) serial for the selection transfer.
         Any asynchronously trapped errors will then cause the
-        selection transfer to be cancelled.  */
+        selection transfer to be canceled.  */
       transfer->serial = (++selection_serial
                          ? selection_serial
                          : ++selection_serial);
diff --git a/src/xterm.c b/src/xterm.c
index d01c4da0564..79648a6d6e5 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -616,9 +616,9 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
     - x_clear_errors
 
   Callers using this set should consult the comment(s) on top of the
-  aformentioned functions.  They should not be used when the requests
+  aforementioned functions.  They should not be used when the requests
   being made do not require roundtrips to the X server, and obtaining
-  the details of any error generated is unecessary, as
+  the details of any error generated is unnecessary, as
   `x_uncatch_errors' will always synchronize with the X server, which
   is a potentially slow operation.  */
 
@@ -5173,7 +5173,7 @@ record_event (char *locus, int type)
 
 
 
-/* Miscelaneous event handling functions.  */
+/* Miscellaneous event handling functions.  */
 
 static void
 x_toolkit_position (struct frame *f, int x, int y,
@@ -11296,7 +11296,7 @@ x_clear_frame (struct frame *f)
 
 /* Send a message to frame F telling the event loop to track whether
    or not an hourglass is being displayed.  This is required to ignore
-   the right events when the hourglass is mapped without callig XSync
+   the right events when the hourglass is mapped without calling XSync
    after displaying or hiding the hourglass.  */
 
 static void
@@ -12564,7 +12564,7 @@ x_dnd_process_quit (struct frame *f, Time timestamp)
 /* This function is defined far away from the rest of the XDND code so
    it can utilize `x_any_window_to_frame'.  */
 
-/* Implementors beware!  On most other platforms (where drag-and-drop
+/* Implementers beware!  On most other platforms (where drag-and-drop
    data is not provided via selections, but some kind of serialization
    mechanism), it is usually much easier to implement a suitable
    primitive instead of copying the C code here, and then to build
@@ -32094,7 +32094,7 @@ x_initialize (void)
 
 #ifdef HAVE_X_I18N
 
-/* Notice that a change has occured on F that requires its input
+/* Notice that a change has occurred on F that requires its input
    method state to be reset.  */
 
 static void
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el 
b/test/lisp/emacs-lisp/bytecomp-tests.el
index 27056c99a50..8fbe48bbb9a 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -717,7 +717,7 @@ inner loops respectively."
       (set (make-local-variable 'bytecomp-tests--xx) 2)
       bytecomp-tests--xx)
 
-    ;; Check for-effect optimisation of `condition-case' body form.
+    ;; Check for-effect optimization of `condition-case' body form.
     ;; With `condition-case' in for-effect context:
     (let ((x (bytecomp-test-identity ?A))
           (r nil))
@@ -797,7 +797,7 @@ inner loops respectively."
     (let ((x 0))
       (list (= (setq x 1))
             x))
-    ;; Aristotelian identity optimisation
+    ;; Aristotelian identity optimization
     (let ((x (bytecomp-test-identity 1)))
       (list (eq x x) (eql x x) (equal x x)))
     )
@@ -2120,7 +2120,7 @@ EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode js-mode 
python-mode)) \
     ))
 
 (ert-deftest bytecomp--byte-op-error-backtrace ()
-  "Check that signalling byte ops show up in the backtrace."
+  "Check that signaling byte ops show up in the backtrace."
   (dolist (case bytecomp-tests--byte-op-error-cases)
     (ert-info ((prin1-to-string case) :prefix "case: ")
       (let* ((call (nth 0 case))
@@ -2151,7 +2151,7 @@ EXPECTED-POINT BINDINGS (MODES \\='\\='(ruby-mode js-mode 
python-mode)) \
                                call))))))))))
 
 (ert-deftest bytecomp--eq-symbols-with-pos-enabled ()
-  ;; Verify that we don't optimise away a binding of
+  ;; Verify that we don't optimize away a binding of
   ;; `symbols-with-pos-enabled' around an application of `eq' (bug#65017).
   (let* ((sym-with-pos1 (read-positioning-symbols "sym"))
          (sym-with-pos2 (read-positioning-symbols " sym"))  ; <- space!
diff --git a/test/lisp/emacs-lisp/ert-font-lock-resources/broken.js 
b/test/lisp/emacs-lisp/ert-font-lock-resources/broken.js
new file mode 100644
index 00000000000..69c1c5cca88
--- /dev/null
+++ b/test/lisp/emacs-lisp/ert-font-lock-resources/broken.js
@@ -0,0 +1,3 @@
+var abc = function(d) {
+//   ^ wrong-face
+};
diff --git a/test/lisp/emacs-lisp/ert-font-lock-resources/correct.js 
b/test/lisp/emacs-lisp/ert-font-lock-resources/correct.js
new file mode 100644
index 00000000000..5e614c64755
--- /dev/null
+++ b/test/lisp/emacs-lisp/ert-font-lock-resources/correct.js
@@ -0,0 +1,3 @@
+var abc = function(d) {
+//   ^ font-lock-variable-name-face
+};
diff --git a/test/lisp/emacs-lisp/ert-font-lock-tests.el 
b/test/lisp/emacs-lisp/ert-font-lock-tests.el
new file mode 100644
index 00000000000..33ef0c6eede
--- /dev/null
+++ b/test/lisp/emacs-lisp/ert-font-lock-tests.el
@@ -0,0 +1,464 @@
+;;; ert-font-lock-tests.el --- ERT Font Lock tests  -*- lexical-binding: t -*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; Author: Vladimir Kazanov
+
+;; 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/>.
+
+;;; Commentary:
+
+;; This file is part of ERT Font Lock, an extension to the Emacs Lisp
+;; Regression Test library (ERT) providing a convenient way to check
+;; syntax highlighting provided by font-lock.
+;;
+;; See ert-font-lock.el for details, and below for example usage of
+;; ert-font-lock facilities.
+
+(require 'ert)
+(require 'ert-x)
+(require 'ert-font-lock)
+
+;;; Helpers
+;;
+
+(defmacro with-temp-buffer-str-mode (mode str &rest body)
+  "Create a buffer with STR contents and MODE. "
+  (declare (indent 1) (debug t))
+  `(with-temp-buffer
+     (insert ,str)
+     (,mode)
+     (goto-char (point-min))
+     ,@body))
+
+;;; Comment parsing tests
+;;
+
+(ert-deftest test-line-comment-p--fundamental ()
+  (with-temp-buffer-str-mode fundamental-mode
+                             "// comment\n"
+                             (should-not (ert-font-lock--line-comment-p))))
+
+(ert-deftest test-line-comment-p--emacs-lisp ()
+  (with-temp-buffer-str-mode emacs-lisp-mode
+                             "not comment
+;; comment
+"
+                             (should-not (ert-font-lock--line-comment-p))
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))
+                             (forward-line)
+                             (should-not (ert-font-lock--line-comment-p))))
+
+(ert-deftest test-line-comment-p--shell-script ()
+  (with-temp-buffer-str-mode shell-script-mode
+                             "echo Not a comment
+# comment
+"
+                             (should-not (ert-font-lock--line-comment-p))
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))))
+
+(declare-function php-mode "php-mode")
+(ert-deftest test-line-comment-p--php ()
+  (skip-unless (featurep 'php-mode))
+
+  (with-temp-buffer-str-mode php-mode
+                             "echo 'Not a comment'
+// comment
+/* comment */
+"
+                             (should-not (ert-font-lock--line-comment-p))
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))))
+
+
+(ert-deftest test-line-comment-p--javascript ()
+  (with-temp-buffer-str-mode javascript-mode
+                             "// comment
+
+   // comment, after a blank line
+
+var abc = function(d) {};
+"
+                             (should (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should-not (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should-not (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should-not (ert-font-lock--line-comment-p))))
+
+(ert-deftest test-line-comment-p--python ()
+
+  (with-temp-buffer-str-mode python-mode
+                             "# comment
+
+   # comment
+print(\"Hello, world!\")"
+                             (should (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should-not (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should-not (ert-font-lock--line-comment-p))))
+
+(ert-deftest test-line-comment-p--c ()
+
+  (with-temp-buffer-str-mode c-mode
+                             "// comment
+/* also comment */"
+                             (should (ert-font-lock--line-comment-p))
+
+                             (forward-line)
+                             (should (ert-font-lock--line-comment-p))))
+
+(ert-deftest test-parse-comments--single-line-error ()
+  (let* ((str "// ^ face.face1"))
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (should-error (ert-font-lock--parse-comments)))))
+
+(ert-deftest test-parse-comments--single-line-single-caret ()
+  (let* ((str "
+first
+// ^ face.face1
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 1))
+      (should (equal (car asserts)
+                     '(:line-checked 2 :line-assert 3 :column-checked 3 :face 
"face.face1" :negation nil))))))
+
+(ert-deftest test-parse-comments--caret-negation ()
+  (let* ((str "
+first
+// ^ !face
+// ^ face
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 2))
+      (should (equal asserts
+                     '((:line-checked 2 :line-assert 3 :column-checked 3 :face 
"face" :negation t)
+                       (:line-checked 2 :line-assert 4 :column-checked 3 :face 
"face" :negation nil)))))))
+
+
+(ert-deftest test-parse-comments--single-line-multiple-carets ()
+  (let* ((str "
+first
+// ^ face1
+//     ^ face.face2
+//     ^ face-face.face3
+   //  ^ face_face.face4
+")
+         asserts)
+
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 4))
+      (should (equal asserts
+                     '((:line-checked 2 :line-assert 3 :column-checked 3 :face 
"face1" :negation nil)
+                       (:line-checked 2 :line-assert 4 :column-checked 7 :face 
"face.face2" :negation nil)
+                       (:line-checked 2 :line-assert 5 :column-checked 7 :face 
"face-face.face3" :negation nil)
+                       (:line-checked 2 :line-assert 6 :column-checked 7 :face 
"face_face.face4" :negation nil)))))))
+
+(ert-deftest test-parse-comments--multiple-line-multiple-carets ()
+  (let* ((str "
+first
+// ^ face1
+second
+// ^ face2
+//   ^ face3
+third
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 3))
+      (should (equal asserts
+                     '((:line-checked 2  :line-assert 3 :column-checked 3 
:face "face1" :negation nil)
+                       (:line-checked 4  :line-assert 5 :column-checked 3 
:face "face2" :negation nil)
+                       (:line-checked 4  :line-assert 6 :column-checked 5 
:face "face3" :negation nil)))))))
+
+
+(ert-deftest test-parse-comments--arrow-single-line-single ()
+  (let* ((str "
+first
+// <- face1
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 1))
+      (should (equal (car asserts)
+                     '(:line-checked 2 :line-assert 3 :column-checked 0 :face 
"face1" :negation nil))))))
+
+
+(ert-deftest test-parse-comments-arrow-multiple-line-single ()
+  (let* ((str "
+first
+// <- face1
+  // <- face2
+    // <- face3
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 3))
+      (should (equal asserts
+                     '((:line-checked 2 :line-assert 3 :column-checked 0 :face 
"face1" :negation nil)
+                       (:line-checked 2 :line-assert 4 :column-checked 2 :face 
"face2" :negation nil)
+                       (:line-checked 2 :line-assert 5 :column-checked 4 :face 
"face3" :negation nil)))))))
+
+(ert-deftest test-parse-comments--non-assert-comment-single ()
+  (let* ((str "
+// first
+//  ^ comment-face
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 1))
+      (should (equal (car asserts)
+                     '(:line-checked 2 :line-assert 3 :column-checked 4 :face 
"comment-face" :negation nil))))))
+
+(ert-deftest test-parse-comments--non-assert-comment-multiple ()
+  (let* ((str "
+// first second third
+//  ^ comment-face
+//        ^ comment-face
+//                ^ comment-face
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 3))
+      (should (equal asserts
+                     '((:line-checked 2 :line-assert 3 :column-checked 4 :face 
"comment-face" :negation nil)
+                       (:line-checked 2 :line-assert 4 :column-checked 10 
:face "comment-face" :negation nil)
+                       (:line-checked 2 :line-assert 5 :column-checked 18 
:face "comment-face" :negation nil)))))))
+
+
+(ert-deftest test-parse-comments--multiline-comment-single ()
+  (let* ((str "
+/*
+  this is a comment
+   ^ comment-face
+ */
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (c-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 1))
+      (should (equal (car asserts)
+                     '(:line-checked 3 :line-assert 4 :column-checked 3 :face 
"comment-face" :negation nil))))))
+
+(ert-deftest test-parse-comments--multiline-comment-multiple ()
+  (let* ((str "
+/*
+  this is a comment
+   ^ comment-face
+  another comment
+    ^ comment-face
+ */
+")
+         asserts)
+    (with-temp-buffer
+      (insert str)
+      (c-mode)
+
+      (setq asserts (ert-font-lock--parse-comments))
+      (should (eql (length asserts) 2))
+      (should (equal asserts
+                     '((:line-checked 3 :line-assert 4 :column-checked 3 :face 
"comment-face" :negation nil)
+                       (:line-checked 5 :line-assert 6 :column-checked 4 :face 
"comment-face" :negation nil)))))))
+
+;;; Syntax highlighting assertion tests
+;;
+
+(ert-deftest test-syntax-highlight-inline--caret-multiple-faces ()
+  (let ((str "
+var abc = function(d) {
+//   ^ font-lock-variable-name-face
+    //        ^ font-lock-keyword-face
+    //             ^ font-lock-variable-name-face
+};
+
+"))
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+      (font-lock-ensure)
+
+      (ert-font-lock--check-faces
+       (ert-font-lock--parse-comments)))))
+
+(ert-deftest test-syntax-highlight-inline--caret-wrong-face ()
+  (let* ((str "
+var abc = function(d) {
+//   ^ not-a-face
+};
+"))
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+      (font-lock-ensure)
+
+      (should-error (ert-font-lock--check-faces
+                     (ert-font-lock--parse-comments))))))
+
+
+(ert-deftest test-syntax-highlight-inline--comment-face ()
+  (let* ((str "
+// this is a comment
+//   ^ font-lock-comment-face
+//       ^ font-lock-comment-face
+//            ^ font-lock-comment-face
+"))
+    (with-temp-buffer
+      (insert str)
+      (javascript-mode)
+      (font-lock-ensure)
+
+      (ert-font-lock--check-faces
+       (ert-font-lock--parse-comments)))))
+
+
+(ert-deftest test-syntax-highlight-inline--multiline-comment-face ()
+  (let* ((str "
+/*
+  this is a comment
+   ^ font-lock-comment-face
+  another comment
+  more comments
+    ^ font-lock-comment-face
+ */
+"))
+    (with-temp-buffer
+      (insert str)
+      (c-mode)
+      (font-lock-ensure)
+
+      (ert-font-lock--check-faces
+       (ert-font-lock--parse-comments)))))
+
+
+(ert-deftest test-font-lock-test-string--correct ()
+  (ert-font-lock-test-string
+   "
+var abc = function(d) {
+// <- font-lock-keyword-face
+//   ^ font-lock-variable-name-face
+    //        ^ font-lock-keyword-face
+    //             ^ font-lock-variable-name-face
+};
+
+"
+   'javascript-mode))
+
+(ert-deftest test-font-lock-test-file--correct ()
+  (ert-font-lock-test-file
+   (ert-resource-file "correct.js")
+   'javascript-mode))
+
+(ert-deftest test-font-lock-test-file--wrong ()
+  :expected-result :failed
+  (ert-font-lock-test-file
+   (ert-resource-file "broken.js")
+   'javascript-mode))
+
+;;; Macro tests
+;;
+
+(ert-font-lock-deftest test-macro-test--correct-highlighting
+    emacs-lisp-mode
+  "
+(defun fun ())
+;; ^ font-lock-keyword-face
+;;      ^ font-lock-function-name-face")
+
+(ert-font-lock-deftest test-macro-test--docstring
+    "A test with a docstring."
+  emacs-lisp-mode
+  "
+(defun fun ())
+;; ^ font-lock-keyword-face"
+  )
+
+(ert-font-lock-deftest test-macro-test--failing
+    "A failing test."
+  :expected-result :failed
+  emacs-lisp-mode
+  "
+(defun fun ())
+;; ^ wrong-face")
+
+(ert-font-lock-deftest-file test-macro-test--file
+    "Test reading correct assertions from a file"
+  javascript-mode
+  "correct.js")
+
+(ert-font-lock-deftest-file test-macro-test--file-failing
+    "Test reading wrong assertions from a file"
+  :expected-result :failed
+  javascript-mode
+  "broken.js")
+
+;;; ert-font-lock-tests.el ends here
diff --git a/test/lisp/erc/erc-fill-tests.el b/test/lisp/erc/erc-fill-tests.el
index bfdf8cd7320..8560d421cc2 100644
--- a/test/lisp/erc/erc-fill-tests.el
+++ b/test/lisp/erc/erc-fill-tests.el
@@ -35,7 +35,8 @@
 
 (defun erc-fill-tests--insert-privmsg (speaker &rest msg-parts)
   (declare (indent 1))
-  (let* ((msg (erc-format-privmessage speaker
+  (let* ((erc--msg-prop-overrides `((erc--msg . msg)))
+         (msg (erc-format-privmessage speaker
                                       (apply #'concat msg-parts) nil t))
          (parsed (make-erc-response :unparsed (format ":%s PRIVMSG #chan :%s"
                                                       speaker msg)
@@ -150,7 +151,9 @@
                                                 "eld"))
          (erc--own-property-names
           (seq-difference `(font-lock-face ,@erc--own-property-names)
-                          '(field display wrap-prefix line-prefix)
+                          `(field display wrap-prefix line-prefix
+                                  erc--msg erc--cmd erc--spkr erc--ts erc--ctcp
+                                  erc--ephemeral)
                           #'eq))
          (print-circle t)
          (print-escape-newlines t)
@@ -165,12 +168,12 @@
       (with-silent-modifications
         (insert (setq got (read repr))))
       (erc-mode))
-    (if erc-fill-tests--save-p
+    ;; LHS is a string, RHS is a symbol.
+    (if (string= erc-fill-tests--save-p (ert-test-name (ert-running-test)))
         (let (inhibit-message)
           (with-temp-file expect-file
             (insert repr))
           ;; Limit writing snapshots to one test at a time.
-          (setq erc-fill-tests--save-p nil)
           (message "erc-fill-tests--compare: wrote %S" expect-file))
       (if (file-exists-p expect-file)
           ;; Ensure string-valued properties, like timestamps, aren't
diff --git a/test/lisp/erc/erc-nicks-tests.el b/test/lisp/erc/erc-nicks-tests.el
index 35264a23caa..54882278139 100644
--- a/test/lisp/erc/erc-nicks-tests.el
+++ b/test/lisp/erc/erc-nicks-tests.el
@@ -409,7 +409,7 @@
              (push-button)
              (should (search-forward-regexp
                       (rx "Foreground: #" (group (+ xdigit)) eol)))
-             (forward-button 1)
+             (forward-button 2) ; skip Inherit:...
              (push-button))
 
            (ert-info ("First entry's sample is rendered correctly")
diff --git a/test/lisp/erc/erc-scenarios-base-attach.el 
b/test/lisp/erc/erc-scenarios-base-attach.el
index ccf5d1f9582..29f5bd2ddd8 100644
--- a/test/lisp/erc/erc-scenarios-base-attach.el
+++ b/test/lisp/erc/erc-scenarios-base-attach.el
@@ -47,11 +47,11 @@
 ;;   Author:     Mario Lang <mlang@delysid.org>
 ;;   AuthorDate: Mon Nov 26 18:33:19 2001 +0000
 ;;
-;;   * new function erc-BBDB-NICK to handle nickname anotation ...
+;;   * new function erc-BBDB-NICK to handle nickname annotation ...
 ;;   * Applied antifuchs/mhp patches, the latest on erc-help, unmodified
 ;;   * New variable: erc-reuse-buffers default to t.
 ;;   * Modified erc-generate-new-buffer-name to use it. it checks if
-;;     server and port are the same, then one can assume thats the same
+;;     server and port are the same, then one can assume that's the same
 ;;     channel/query target again.
 
 ;;; Code:
diff --git a/test/lisp/erc/erc-scenarios-base-reconnect.el 
b/test/lisp/erc/erc-scenarios-base-reconnect.el
index 7bd16d1ed14..163521f4a7b 100644
--- a/test/lisp/erc/erc-scenarios-base-reconnect.el
+++ b/test/lisp/erc/erc-scenarios-base-reconnect.el
@@ -171,7 +171,7 @@
           (funcall expect 2 "Canceled")
           (funcall expect 3 "Opening connection")
           (funcall expect 2 "Password incorrect")
-          (funcall expect 2 "Connection failed!")
+          (funcall expect 10 "Connection failed!")
           (funcall expect 2 "Re-establishing connection"))
         (ert-info ("Explicitly cancel timer")
           (erc-cmd-RECONNECT "cancel")
diff --git a/test/lisp/erc/erc-scenarios-base-renick.el 
b/test/lisp/erc/erc-scenarios-base-renick.el
index 5a87e5871f7..689f962812a 100644
--- a/test/lisp/erc/erc-scenarios-base-renick.el
+++ b/test/lisp/erc/erc-scenarios-base-renick.el
@@ -267,7 +267,7 @@
 
     (ert-info ("Sync convo for rando@foonet")
       (with-current-buffer "rando@foonet"
-        (funcall expect 1 "u are dumb")
+        (funcall expect 10 "u are dumb")
         (erc-scenarios-common-say "not so")))
 
     (ert-info ("Sync convo for rando@barnet")
diff --git a/test/lisp/erc/erc-scenarios-base-statusmsg.el 
b/test/lisp/erc/erc-scenarios-base-statusmsg.el
new file mode 100644
index 00000000000..80582e0cf80
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-statusmsg.el
@@ -0,0 +1,103 @@
+;;; erc-scenarios-base-statusmsg.el --- statusmsg tests -*- lexical-binding: t 
-*-
+
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; 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/>.
+
+;;; Code:
+
+(require 'ert-x)
+(eval-and-compile
+  (let ((load-path (cons (ert-resource-directory) load-path)))
+    (require 'erc-scenarios-common)))
+
+(ert-deftest erc-scenarios-base-statusmsg ()
+
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/display-message")
+       (dumb-server (erc-d-run "localhost" t 'statusmsg))
+       (erc-autojoin-channels-alist '((foonet "#mine")))
+       (erc-modules (cons 'fill-wrap erc-modules))
+       (port (process-contact dumb-server :service))
+       (erc-show-speaker-membership-status nil)
+       (erc-server-flood-penalty 0.1)
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester"
+                                :full-name "tester")
+        (funcall expect 5 "This server is in debug mode")))
+
+    (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#mine"))
+
+      (ert-info ("Receive status messages unprefixed")
+        (funcall expect 5 "+dummy")
+        (funcall expect 5 "(dummy+) hello")
+        (should (eq 'statusmsg (erc--get-inserted-msg-prop 'erc--msg)))
+        (should (equal "dummy" (erc--get-inserted-msg-prop 'erc--spkr)))
+        (should (eq (get-text-property (1- (point)) 'font-lock-face)
+                    'erc-default-face))
+        (funcall expect 5 "(dummy+) there")
+        (should (equal "" (get-text-property (pos-bol) 'display)))
+
+        ;; CTCP ACTION
+        (funcall expect 5 "* (dummy+) sad")
+        (should (eq 'ctcp-action-statusmsg
+                    (erc--get-inserted-msg-prop 'erc--msg)))
+        (should (eq (get-text-property (1- (point)) 'font-lock-face)
+                    'erc-action-face))
+        (funcall expect 5 "* (dummy+) glad")
+        (should (equal "" (get-text-property (pos-bol) 'display))))
+
+      (ert-info ("Send status messages")
+        ;; We don't have `echo-message' yet, so ERC doesn't currently
+        ;; insert commands like "/msg +#mine foo".
+        (let ((erc-default-recipients '("+#mine")))
+          (erc-send-message "howdy"))
+        (funcall expect 5 "(@tester+) howdy")
+        (should (eq 'statusmsg-input (erc--get-inserted-msg-prop 'erc--msg)))
+        (should (equal "tester" (erc--get-inserted-msg-prop 'erc--spkr)))
+        (should (eq (get-text-property (1- (point)) 'font-lock-face)
+                    'erc-input-face))
+        (let ((erc-default-recipients '("+#mine")))
+          (erc-send-message "tenderfoot"))
+        (funcall expect 5 "(@tester+) tenderfoot")
+        (should (equal "" (get-text-property (pos-bol) 'display)))
+
+        ;; Simulate some "echoed" CTCP ACTION messages since we don't
+        ;; actually support that yet.
+        (funcall expect 5 "* (@tester+) mad")
+        (should (eq 'ctcp-action-statusmsg-input
+                    (erc--get-inserted-msg-prop 'erc--msg)))
+        (should (equal (get-text-property (1- (point)) 'font-lock-face)
+                       '(erc-input-face erc-action-face)))
+        (funcall expect 5 "* (@tester+) chad")
+        (should (equal "" (get-text-property (pos-bol) 'display))))
+
+      (ert-info ("Receive status messages prefixed")
+        (setq erc-show-speaker-membership-status t)
+        (erc-scenarios-common-say "/me ready") ; sync
+        (funcall expect 5 "* @tester ready")
+        (funcall expect 5 "(+dummy+) okie")
+
+        ;; CTCP ACTION
+        (funcall expect 5 "* (+dummy+) dokie")
+        (funcall expect 5 "* +dummy out")))))
+
+;;; erc-scenarios-base-statusmsg.el ends here
diff --git a/test/lisp/erc/erc-scenarios-display-message.el 
b/test/lisp/erc/erc-scenarios-display-message.el
index c7e0c2fc17a..91b82889f3e 100644
--- a/test/lisp/erc/erc-scenarios-display-message.el
+++ b/test/lisp/erc/erc-scenarios-display-message.el
@@ -50,12 +50,12 @@
       (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "dummy"))
         (funcall expect 10 "<dummy> hi")
         (funcall expect 10 "*** dummy (~u@rdjcgiwfuwqmc.irc) has quit")
-        (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)))))
+        (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc--msg)))))
 
     (ert-info ("Dummy's QUIT notice in #chan contains metadata props")
       (with-current-buffer (erc-d-t-wait-for 5 (get-buffer "#chan"))
         (funcall expect 10 "*** dummy (~u@rdjcgiwfuwqmc.irc) has quit")
-        (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc-msg)))))
+        (should (eq 'QUIT (get-text-property (match-beginning 0) 'erc--msg)))))
 
     (with-current-buffer "foonet"
       (erc-cmd-QUIT ""))))
diff --git a/test/lisp/erc/erc-scenarios-match.el 
b/test/lisp/erc/erc-scenarios-match.el
index 17f7649566e..0eed1853879 100644
--- a/test/lisp/erc/erc-scenarios-match.el
+++ b/test/lisp/erc/erc-scenarios-match.el
@@ -304,9 +304,9 @@
                (should (= mend (field-end right-stamp)))
                (should (eq (field-at-pos (1- mend)) 'erc-timestamp))))
 
-           ;; The `erc-ts' property is present in prop stack.
-           (should (get-text-property (pos-bol) 'erc-ts))
-           (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts))
+           ;; The `erc--ts' property is present in prop stack.
+           (should (get-text-property (pos-bol) 'erc--ts))
+           (should-not (next-single-property-change (1+ (pos-bol)) 'erc--ts))
 
            ;; Line ending has the `invisible' property `match-fools'.
            (should (eq (get-text-property mbeg 'invisible) 'match-fools))
@@ -413,7 +413,7 @@
         (should-not (equal "" (get-text-property (pos-bol) 'display)))
 
         ;; No remaining meta-data positions, no more timestamps.
-        (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts))
+        (should-not (next-single-property-change (1+ (pos-bol)) 'erc--ts))
         ;; No remaining invisible messages.
         (should-not (text-property-not-all (pos-bol) erc-insert-marker
                                            'invisible nil))
@@ -456,10 +456,10 @@
              (should (eq (field-at-pos (field-end mbeg)) 'erc-timestamp))
              (should (eq (field-at-pos (1- mend)) 'erc-timestamp)))
 
-           ;; The `erc-ts' property is present in the message's
+           ;; The `erc--ts' property is present in the message's
            ;; width 1 prop collection at its first char.
-           (should (get-text-property (pos-bol) 'erc-ts))
-           (should-not (next-single-property-change (1+ (pos-bol)) 'erc-ts))
+           (should (get-text-property (pos-bol) 'erc--ts))
+           (should-not (next-single-property-change (1+ (pos-bol)) 'erc--ts))
 
            ;; Line ending has the `invisible' property `match-fools'.
            (should (= (char-after mend) ?\n))
diff --git a/test/lisp/erc/erc-scenarios-misc-commands.el 
b/test/lisp/erc/erc-scenarios-misc-commands.el
index 2a36d52b835..b96782cf29c 100644
--- a/test/lisp/erc/erc-scenarios-misc-commands.el
+++ b/test/lisp/erc/erc-scenarios-misc-commands.el
@@ -91,4 +91,36 @@
         (funcall expect -0.1 "Incorrect arguments")
         (funcall expect 10 "See also: HELP EXAMPLES")))))
 
+;; Note that as of ERC 5.6, there is no actual slash-command function
+;; named `erc-cmd-vhost'.  At the moment, this test merely exists to
+;; assert that the `erc-server-396' response handler updates the rolls
+;; correctly.
+(ert-deftest erc-scenarios-misc-commands--VHOST ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "commands")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'vhost))
+       ;; As of ERC 5.6, we must join a channel before ERC adds itself
+       ;; to `erc-server-users'.  Without such an entry, there's
+       ;; nothing to update when the 396 arrives.
+       (erc-autojoin-channels-alist '((foonet "#chan")))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter)))
+
+    (ert-info ("Connect to server")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :password "changeme"
+                                :full-name "tester")
+        (funcall expect 10 "debug mode")))
+
+    (ert-info ("Send VHOST")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (erc-scenarios-common-say "/VHOST tester changeme")
+        (funcall expect 10 "visible host")
+        (should (string= (erc-server-user-host (erc-get-server-user "tester"))
+                         "some.host.test.cc"))))))
+
 ;;; erc-scenarios-misc-commands.el ends here
diff --git a/test/lisp/erc/erc-scenarios-stamp.el 
b/test/lisp/erc/erc-scenarios-stamp.el
index 49307dd228a..e4788f78654 100644
--- a/test/lisp/erc/erc-scenarios-stamp.el
+++ b/test/lisp/erc/erc-scenarios-stamp.el
@@ -29,7 +29,7 @@
 (defvar erc-scenarios-stamp--user-marker nil)
 
 (defun erc-scenarios-stamp--on-post-modify ()
-  (when-let (((erc--check-msg-prop 'erc-cmd 4)))
+  (when-let (((erc--check-msg-prop 'erc--cmd 4)))
     (set-marker erc-scenarios-stamp--user-marker (point-max))
     (ert-info ("User marker correctly placed at `erc-insert-marker'")
       (should (= ?\n (char-before erc-scenarios-stamp--user-marker)))
@@ -68,11 +68,11 @@
         (ert-info ("Stamps appear in left margin and are invisible")
           (should (eq 'erc-timestamp (field-at-pos (pos-bol))))
           (should (= (pos-bol) (field-beginning (pos-bol))))
-          (should (eq 'msg (get-text-property (pos-bol) 'erc-msg)))
-          (should (eq 'NOTICE (get-text-property (pos-bol) 'erc-cmd)))
+          (should (eq 'query-notice (get-text-property (pos-bol) 'erc--msg)))
+          (should (eq 'NOTICE (get-text-property (pos-bol) 'erc--cmd)))
           (should (= ?- (char-after (field-end (pos-bol)))))
           (should (equal (get-text-property (1+ (field-end (pos-bol)))
-                                            'erc-speaker)
+                                            'erc--speaker)
                          "irc.foonet.org"))
           (should (pcase (get-text-property (pos-bol) 'display)
                     (`((margin left-margin) ,s)
@@ -104,14 +104,14 @@
           (funcall expect 5 "Opening connection")
           (goto-char (1- (match-beginning 0)))
           (should (eq 'erc-timestamp (field-at-pos (point))))
-          (should (eq 'unknown (erc--get-inserted-msg-prop 'erc-msg)))
+          (should (eq 'unknown (erc--get-inserted-msg-prop 'erc--msg)))
           ;; Force redraw of date stamp.
           (setq erc-timestamp-last-inserted-left nil)
 
           (funcall expect 5 "This server is in debug mode")
           (while (and (zerop (forward-line -1))
                       (not (eq 'erc-timestamp (field-at-pos (point))))))
-          (should (erc--get-inserted-msg-prop 'erc-cmd)))))))
+          (should (erc--get-inserted-msg-prop 'erc--cmd)))))))
 
 ;; This user-owned hook member places a marker on the first message in
 ;; a buffer.  Inserting a date stamp in front of it shouldn't move the
@@ -125,18 +125,18 @@
 
   ;; Sometime after the first message ("Opening connection.."), assert
   ;; that the marker we just placed hasn't moved.
-  (when (erc--check-msg-prop 'erc-cmd 2)
+  (when (erc--check-msg-prop 'erc--cmd 2)
     (save-restriction
       (widen)
       (ert-info ("Date stamp preserves opening user marker")
         (goto-char erc-scenarios-stamp--user-marker)
         (should-not (eq 'erc-timestamp (field-at-pos (point))))
         (should (looking-at "Opening"))
-        (should (eq 'unknown (get-text-property (point) 'erc-msg))))))
+        (should (eq 'unknown (get-text-property (point) 'erc--msg))))))
 
   ;; On 003 ("*** This server was created on"), clear state to force a
   ;; new date stamp on the next message.
-  (when (erc--check-msg-prop 'erc-cmd 3)
+  (when (erc--check-msg-prop 'erc--cmd 3)
     (setq erc-timestamp-last-inserted-left nil)
     (set-marker erc-scenarios-stamp--user-marker erc-insert-marker)))
 
@@ -174,7 +174,7 @@
           (goto-char erc-scenarios-stamp--user-marker)
           (should-not (eq 'erc-timestamp (field-at-pos (point))))
           (should (looking-at (rx "*** irc.foonet.org oragono")))
-          (should (eq 's004 (get-text-property (point) 'erc-msg))))
+          (should (eq 's004 (get-text-property (point) 'erc--msg))))
 
         (funcall expect 5 "This server is in debug mode")))))
 
diff --git a/test/lisp/erc/erc-stamp-tests.el b/test/lisp/erc/erc-stamp-tests.el
index cc61d599387..fd2e7000c0e 100644
--- a/test/lisp/erc/erc-stamp-tests.el
+++ b/test/lisp/erc/erc-stamp-tests.el
@@ -279,7 +279,7 @@
 
   (should-not erc-echo-timestamps)
   (should-not erc-stamp--last-stamp)
-  (insert (propertize "a" 'erc-ts 433483200 'erc-msg 'msg) "bc")
+  (insert (propertize "a" 'erc--ts 433483200 'erc--msg 'msg) "bc")
   (goto-char (point-min))
   (let ((inhibit-message t)
         (erc-echo-timestamp-format "%Y-%m-%d %H:%M:%S %Z")
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 912a85ad5e0..45cf4ea489f 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -142,6 +142,19 @@
                                     (widget-editable-list-match w v))
                    '(face)))))
 
+(ert-deftest erc--doarray ()
+  (let ((array "abcdefg")
+        out)
+    ;; No return form.
+    (should-not (erc--doarray (c array) (push c out)))
+    (should (equal out '(?g ?f ?e ?d ?c ?b ?a)))
+
+    ;; Return form evaluated upon completion.
+    (setq out nil)
+    (should (= 42 (erc--doarray (c array (+ 39 (length out)))
+                    (when (cl-evenp c) (push c out)))))
+    (should (equal out '(?f ?d ?b)))))
+
 (defun erc-tests--send-prep ()
   ;; Caller should probably shadow `erc-insert-modify-hook' or
   ;; populate user tables for erc-button.
@@ -619,8 +632,6 @@
     (should (string= "nick" (erc-lurker-maybe-trim "nick-_`")))))
 
 (ert-deftest erc-parse-user ()
-  (should (equal erc--parse-user-regexp erc--parse-user-regexp-legacy))
-
   (should (equal '("" "" "") (erc-parse-user "!@")))
   (should (equal '("" "!" "") (erc-parse-user "!!@")))
   (should (equal '("" "" "@") (erc-parse-user "!@@")))
@@ -633,23 +644,36 @@
   (should (equal '("abc" "123" "fake") (erc-parse-user "abc!123@fake")))
   (should (equal '("abc" "!123" "@xy") (erc-parse-user "abc!!123@@xy")))
 
-  (should (equal '("de" "fg" "xy") (erc-parse-user "abc\nde!fg@xy")))
+  (should (equal '("de" "fg" "xy") (erc-parse-user "abc\nde!fg@xy"))))
+
+(ert-deftest erc--parse-nuh ()
+  (should (equal '(nil nil nil) (erc--parse-nuh "!@")))
+  (should (equal '(nil nil nil) (erc--parse-nuh "@")))
+  (should (equal '(nil nil nil) (erc--parse-nuh "!")))
+  (should (equal '(nil "!" nil) (erc--parse-nuh "!!@")))
+  (should (equal '(nil "@" nil) (erc--parse-nuh "!@@")))
+  (should (equal '(nil "!@" nil) (erc--parse-nuh "!!@@")))
 
-  (ert-info ("`erc--parse-user-regexp-pedantic'")
-    (let ((erc--parse-user-regexp erc--parse-user-regexp-pedantic))
-      (should (equal '("" "" "") (erc-parse-user "!@")))
-      (should (equal '("" "!" "") (erc-parse-user "!!@")))
-      (should (equal '("" "@" "") (erc-parse-user "!@@")))
-      (should (equal '("" "!@" "") (erc-parse-user "!!@@")))
+  (should (equal '("abc" nil nil) (erc--parse-nuh "abc!")))
+  (should (equal '(nil "abc" nil) (erc--parse-nuh "abc@")))
+  (should (equal '(nil "abc" nil) (erc--parse-nuh "!abc@")))
 
-      (should (equal '("abc" "" "") (erc-parse-user "abc")))
-      (should (equal '("" "123" "fake") (erc-parse-user "!123@fake")))
-      (should (equal '("abc" "" "123") (erc-parse-user "abc!123")))
+  (should (equal '("abc" "123" "fake") (erc--parse-nuh "abc!123@fake")))
+  (should (equal '("abc" "!123@" "xy") (erc--parse-nuh "abc!!123@@xy")))
 
-      (should (equal '("abc" "123" "fake") (erc-parse-user "abc!123@fake")))
-      (should (equal '("abc" "!123@" "xy") (erc-parse-user "abc!!123@@xy")))
+  ;; Missing leading components.
+  (should (equal '(nil "abc" "123") (erc--parse-nuh "abc@123")))
+  (should (equal '(nil "123" "fake") (erc--parse-nuh "!123@fake")))
+  (should (equal '(nil nil "gnu.org") (erc--parse-nuh "@gnu.org")))
 
-      (should (equal '("de" "" "fg@xy") (erc-parse-user "abc\nde!fg@xy"))))))
+  ;; Host "wins" over nick and user (sans "@").
+  (should (equal '(nil nil "abc") (erc--parse-nuh "abc")))
+  (should (equal '(nil nil "gnu.org") (erc--parse-nuh "gnu.org")))
+  (should (equal '(nil nil "gnu.org") (erc--parse-nuh "!gnu.org")))
+  (should (equal '("abc" nil "123") (erc--parse-nuh "abc!123")))
+
+  ;; No fallback behavior.
+  (should-not (erc--parse-nuh "abc\nde!fg@xy")))
 
 (ert-deftest erc--parsed-prefix ()
   (erc-mode)
@@ -657,7 +681,7 @@
   (setq erc--isupport-params (make-hash-table))
 
   ;; Uses fallback values when no PREFIX parameter yet received, thus
-  ;; ensuring caller can use slot accessors immediately intead of
+  ;; ensuring caller can use slot accessors immediately instead of
   ;; checking if null beforehand.
   (should-not erc--parsed-prefix)
   (should (equal (erc--parsed-prefix)
@@ -1390,9 +1414,9 @@
        (ert-info ("Input remains untouched")
          (should (save-excursion (erc-bol) (looking-at "/msg #chan hi")))))
 
-     (ert-info ("Errors when no process running")
+     (ert-info ("Errors when server buffer absent")
        (let ((e (should-error (erc-send-current-line))))
-         (should (equal "ERC: No process running" (cadr e))))
+         (should (equal "Server buffer missing" (cadr e))))
        (ert-info ("Input remains untouched")
          (should (save-excursion (erc-bol) (looking-at "/msg #chan hi")))))
 
@@ -1738,7 +1762,7 @@
                                    :command "PRIVMSG"
                                    :command-args (list "#chan" "hi")
                                    :contents "hi"))
-        (erc--msg-prop-overrides '((erc-ts . 0))))
+        (erc--msg-prop-overrides '((erc--ts . 0))))
     (erc-display-message parsed nil (current-buffer)
                          (erc-format-privmessage "bob" "hi" nil t)))
   (goto-char 3)
@@ -1785,7 +1809,7 @@
   ;; Put unique invisible properties on the line endings.
   (erc-display-message nil 'notice nil "one")
   (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible 'a)
-  (let ((erc--msg-prop-overrides '((erc-msg . datestamp) (erc-ts . 0))))
+  (let ((erc--msg-prop-overrides '((erc--msg . datestamp) (erc--ts . 0))))
     (erc-display-message nil nil nil
                          (propertize "\n[date]" 'field 'erc-timestamp)))
   (put-text-property (1- erc-insert-marker) erc-insert-marker 'invisible 'b)
@@ -1794,7 +1818,7 @@
   (ert-info ("Date stamp deleted cleanly")
     (goto-char 11)
     (should (looking-at (rx "\n[date]")))
-    (should (eq 'datestamp (get-text-property (point) 'erc-msg)))
+    (should (eq 'datestamp (get-text-property (point) 'erc--msg)))
     (should (eq (point) (field-beginning (1+ (point)))))
 
     (erc--delete-inserted-message (point))
@@ -1855,19 +1879,21 @@
 
 (ert-deftest erc--order-text-properties-from-hash ()
   (let ((table (map-into '((a . 1)
-                           (erc-ts . 0)
-                           (erc-msg . s005)
+                           (erc--ts . 0)
+                           (erc--msg . s005)
                            (b . 2)
-                           (erc-cmd . 5)
+                           (erc--cmd . 5)
+                           (erc--spkr . "X")
                            (c . 3))
                          'hash-table)))
     (with-temp-buffer
       (erc-mode)
       (insert "abc\n")
       (add-text-properties 1 2 (erc--order-text-properties-from-hash table))
-      (should (equal '( erc-msg s005
-                        erc-ts 0
-                        erc-cmd 5
+      (should (equal '( erc--msg s005
+                        erc--spkr "X"
+                        erc--ts 0
+                        erc--cmd 5
                         a 1
                         b 2
                         c 3)
@@ -2241,10 +2267,11 @@
               erc-pre-send-functions
               (lambda (o) (setf (erc-input-string o) "foo bar baz"
                                 (erc-input-refoldp o) t)))
-        (let ((erc-split-line-length 8))
+        (let* ((split (make-erc--input-split :string "foo" :lines '("foo")))
+               (erc--current-line-input-split split)
+               (erc-split-line-length 8))
           (should
-           (pcase (erc--run-send-hooks (make-erc--input-split
-                                        :string "foo" :lines '("foo")))
+           (pcase (erc--run-send-hooks split)
              ((cl-struct erc--input-split
                          (string "foo") (sendp 't) (insertp 't)
                          (lines '("foo bar " "baz")) (cmdp 'nil))
@@ -2258,7 +2285,8 @@
         calls
         erc-kill-channel-hook erc-kill-server-hook erc-kill-buffer-hook)
     (cl-letf (((symbol-function 'erc-display-message)
-               (lambda (_ _ _ line) (push line calls)))
+               (lambda (_ _ _ msg &rest args)
+                 (push (apply #'erc-format-message msg args) calls)))
               ((symbol-function 'erc-server-send)
                (lambda (line _) (push line calls)))
               ((symbol-function 'erc-server-buffer)
@@ -2300,7 +2328,7 @@
           (should-not erc-server-last-peers)
           (erc-message "PRIVMSG" ". hi")
           (should-not erc-server-last-peers)
-          (should (eq 'no-target (pop calls)))
+          (should (equal "No target" (pop calls)))
           (erc-message "PRIVMSG" ", hi")
           (should-not erc-server-last-peers)
           (should (string-match "alice :hi" (pop calls)))))
@@ -2333,42 +2361,208 @@
     (kill-buffer "ExampleNet")
     (kill-buffer "#chan")))
 
-(ert-deftest erc-format-privmessage ()
-  ;; Basic PRIVMSG
-  (should (erc-tests--equal-including-properties
-           (erc-format-privmessage (copy-sequence "bob")
-                                   (copy-sequence "oh my")
-                                   nil 'msgp)
-           #("<bob> oh my"
-             0 1 (font-lock-face erc-default-face)
-             1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face)
-             4 11 (font-lock-face erc-default-face))))
-
-  ;; Basic NOTICE
-  (should (erc-tests--equal-including-properties
-           (erc-format-privmessage (copy-sequence "bob")
-                                   (copy-sequence "oh my")
-                                   nil nil)
-           #("-bob- oh my"
-             0 1 (font-lock-face erc-default-face)
-             1 4 (erc-speaker "bob" font-lock-face erc-nick-default-face)
-             4 11 (font-lock-face erc-default-face))))
-
-  ;; Prefixed PRIVMSG
-  (let* ((user (make-erc-server-user :nickname (copy-sequence "Bob")))
+;; This is an adapter that uses formatting templates from the
+;; `-speaker' catalog to mimic `erc-format-privmessage', for testing
+;; purposes.
+(defun erc-tests--format-privmessage (nick msg privp msgp &optional inputp pfx)
+  (let ((erc-current-message-catalog erc--message-speaker-catalog))
+    (apply #'erc-format-message
+           (erc--determine-speaker-message-format-args nick msg privp msgp
+                                                       inputp nil pfx))))
+
+;; This asserts that `erc--determine-speaker-message-format-args'
+;; behaves identically to `erc-format-privmessage', the function whose
+;; role it basically replaced.
+(ert-deftest erc--determine-speaker-message-format-args ()
+  ;; Basic PRIVMSG.
+  (let ((expect #("<bob> oh my"
+                  0 1 (font-lock-face erc-default-face)
+                  1 4 (erc--speaker "bob" font-lock-face erc-nick-default-face)
+                  4 11 (font-lock-face erc-default-face)))
+        (args (list (concat "bob") (concat "oh my") nil 'msgp)))
+    (should (erc-tests--equal-including-properties
+             (apply #'erc-format-privmessage args)
+             expect))
+    (should (erc-tests--equal-including-properties
+             (apply #'erc-tests--format-privmessage args)
+             expect)))
+
+  ;; Basic NOTICE.
+  (let ((expect #("-bob- oh my"
+                  0 1 (font-lock-face erc-default-face)
+                  1 4 (erc--speaker "bob" font-lock-face erc-nick-default-face)
+                  4 11 (font-lock-face erc-default-face)))
+        (args (list (copy-sequence "bob") (copy-sequence "oh my") nil nil)))
+    (should (erc-tests--equal-including-properties
+             (apply #'erc-format-privmessage args)
+             expect))
+    (should (erc-tests--equal-including-properties
+             (apply #'erc-tests--format-privmessage args)
+             expect)))
+
+  ;; Status-prefixed PRIVMSG.
+  (let* ((expect
+          #("<@Bob> oh my"
+            0 1 (font-lock-face erc-default-face)
+            1 2 (font-lock-face erc-nick-prefix-face help-echo "operator")
+            2 5 (erc--speaker "Bob" font-lock-face erc-nick-default-face)
+            5 12 (font-lock-face erc-default-face)))
+         (user (make-erc-server-user :nickname (copy-sequence "Bob")))
          (cuser (make-erc-channel-user :op t))
          (erc-channel-users (make-hash-table :test #'equal)))
     (puthash "bob" (cons user cuser) erc-channel-users)
 
+    (with-suppressed-warnings ((obsolete erc-format-@nick))
+      (should (erc-tests--equal-including-properties
+               (erc-format-privmessage (erc-format-@nick user cuser)
+                                       (copy-sequence "oh my")
+                                       nil 'msgp)
+               expect)))
+    (let ((nick "Bob")
+          (msg "oh my"))
+      (should (erc-tests--equal-including-properties
+               (erc-tests--format-privmessage nick msg nil 'msgp nil cuser)
+               expect)) ; overloaded on PREFIX arg
+      (should (erc-tests--equal-including-properties
+               (erc-tests--format-privmessage nick msg nil 'msgp nil t)
+               expect))
+      ;; The new version makes a copy instead of adding properties to
+      ;; the input.
+      (should-not
+       (text-property-not-all 0 (length nick) 'font-lock-face nil nick))
+      (should-not
+       (text-property-not-all 0 (length msg) 'font-lock-face nil msg)))))
+
+(ert-deftest erc--determine-speaker-message-format-args/queries-as-channel ()
+  (should erc-format-query-as-channel-p)
+
+  (with-current-buffer (get-buffer-create "bob")
+    (erc-mode)
+    (setq erc--target (erc--target-from-string "alice"))
+
+    (insert "PRIVMSG\n"
+            (erc-tests--format-privmessage "bob" "oh my" 'queryp 'msgp))
+    (should (erc-tests--equal-including-properties
+             #("<bob> oh my"
+               0 1 (font-lock-face erc-default-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-nick-default-face)
+               4 11 (font-lock-face erc-default-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (insert "\nNOTICE\n"
+            (erc-tests--format-privmessage "bob" "oh my" 'queryp nil))
+    (should (erc-tests--equal-including-properties
+             #("-bob- oh my"
+               0 1 (font-lock-face erc-default-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-nick-default-face)
+               4 11 (font-lock-face erc-default-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (insert "\nInput PRIVMSG\n"
+            (erc-tests--format-privmessage "bob" "oh my"
+                                           'queryp 'privmsgp 'inputp))
     (should (erc-tests--equal-including-properties
-             (erc-format-privmessage (erc-format-@nick user cuser)
-                                     (copy-sequence "oh my")
-                                     nil 'msgp)
-             #("<@Bob> oh my"
+             #("<bob> oh my"
                0 1 (font-lock-face erc-default-face)
-               1 2 (font-lock-face erc-nick-prefix-face help-echo "operator")
-               2 5 (erc-speaker "Bob" font-lock-face erc-nick-default-face)
-               5 12 (font-lock-face erc-default-face))))))
+               1 4 (erc--speaker "bob" font-lock-face erc-my-nick-face)
+               4 6 (font-lock-face erc-default-face)
+               6 11 (font-lock-face erc-input-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (insert "\nInput NOTICE\n"
+            (erc-tests--format-privmessage "bob" "oh my" 'queryp nil 'inputp))
+    (should (erc-tests--equal-including-properties
+             #("-bob- oh my"
+               0 1 (font-lock-face erc-default-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-my-nick-face)
+               4 6 (font-lock-face erc-default-face)
+               6 11 (font-lock-face erc-input-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (when noninteractive (kill-buffer))))
+
+(ert-deftest erc--determine-speaker-message-format-args/queries ()
+  (should erc-format-query-as-channel-p)
+
+  (with-current-buffer (get-buffer-create "bob")
+    (erc-mode)
+    (setq-local erc-format-query-as-channel-p nil)
+    (setq erc--target (erc--target-from-string "alice"))
+
+    (insert "PRIVMSG\n"
+            (erc-tests--format-privmessage "bob" "oh my" 'queryp 'msgp))
+    (should (erc-tests--equal-including-properties
+             #("*bob* oh my"
+               0 1 (font-lock-face erc-direct-msg-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-nick-msg-face)
+               4 11 (font-lock-face erc-direct-msg-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (insert "\nNOTICE\n"
+            (erc-tests--format-privmessage "bob" "oh my" 'queryp nil))
+    (should (erc-tests--equal-including-properties
+             #("-bob- oh my"
+               0 1 (font-lock-face erc-direct-msg-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-nick-msg-face)
+               4 11 (font-lock-face erc-direct-msg-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (insert "\nInput PRIVMSG\n"
+            (erc-tests--format-privmessage "bob" "oh my"
+                                           'queryp 'privmsgp 'inputp))
+    (should (erc-tests--equal-including-properties
+             #("*bob* oh my"
+               0 1 (font-lock-face erc-direct-msg-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-my-nick-face)
+               4 6 (font-lock-face erc-direct-msg-face)
+               6 11 (font-lock-face erc-input-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (insert "\nInput NOTICE\n"
+            (erc-tests--format-privmessage "bob" "oh my" 'queryp nil 'inputp))
+    (should (erc-tests--equal-including-properties
+             #("-bob- oh my"
+               0 1 (font-lock-face erc-direct-msg-face)
+               1 4 (erc--speaker "bob" font-lock-face erc-my-nick-face)
+               4 6 (font-lock-face erc-direct-msg-face)
+               6 11 (font-lock-face erc-input-face))
+             (buffer-substring (pos-bol) (pos-eol))))
+
+    (when noninteractive (kill-buffer))))
+
+(defun erc-tests--format-my-nick (message)
+  (concat (erc-format-my-nick)
+          (propertize message 'font-lock-face 'erc-input-face)))
+
+;; This tests that the default behavior of the replacement formatting
+;; function for prompt input, `erc--format-speaker-input-message'
+;; matches that of the original being replaced, `erc-format-my-nick',
+;; though it only handled the speaker portion.
+(ert-deftest erc--format-speaker-input-message ()
+  ;; No status prefix.
+  (let ((erc-server-current-nick "tester")
+        (expect #("<tester> oh my"
+                  0 1 (font-lock-face erc-default-face)
+                  1 7 (font-lock-face erc-my-nick-face erc--speaker "tester")
+                  7 9 (font-lock-face erc-default-face)
+                  9 14 (font-lock-face erc-input-face))))
+    (should (equal (erc-tests--format-my-nick "oh my") expect))
+    (should (equal (erc--format-speaker-input-message "oh my") expect)))
+
+  ;; With channel-operator status prefix.
+  (let* ((erc-server-current-nick "tester")
+         (cmem (cons (make-erc-server-user :nickname "tester")
+                     (make-erc-channel-user :op t)))
+         (erc-channel-users (map-into (list "tester" cmem)
+                                      '(hash-table :test equal)))
+         (expect #("<@tester> oh my"
+                   0 1 (font-lock-face erc-default-face)
+                   1 2 (font-lock-face erc-my-nick-prefix-face)
+                   2 5 (font-lock-face erc-my-nick-face erc--speaker "bob")
+                   5 7 (font-lock-face erc-default-face)
+                   7 12 (font-lock-face erc-input-face))))
+    (should (equal (erc-tests--format-my-nick "oh my") expect))
+    (should (equal (erc--format-speaker-input-message "oh my") expect))))
 
 (ert-deftest erc--route-insertion ()
   (erc-tests--send-prep)
@@ -2392,7 +2586,7 @@
 
         (ert-info ("Cons `buffer' routes to live members")
           ;; Copies a let-bound `erc--msg-props' before mutating.
-          (let* ((table (map-into '(erc-msg msg) 'hash-table))
+          (let* ((table (map-into '(erc--msg msg) 'hash-table))
                  (erc--msg-props table))
             (erc--route-insertion "cons" (list server-buffer spam-buffer))
             (should-not (eq table erc--msg-props)))
@@ -2852,6 +3046,57 @@
     (kill-buffer "baznet")
     (kill-buffer "#chan")))
 
+(ert-deftest erc-channel-user ()
+  ;; Traditional and alternate constructor swapped for compatibility.
+  (should (= 0 (erc-channel-user-status (erc-channel-user--make))))
+  (should-not (erc-channel-user-last-message-time (erc-channel-user--make)))
+
+  (should (= 42 (erc-channel-user-last-message-time
+                 (make-erc-channel-user :last-message-time 42))))
+
+  (should (zerop (erc-channel-user-status (make-erc-channel-user))))
+
+  (let ((u (make-erc-channel-user)))
+
+    (ert-info ("Add voice status to user")
+      (should (= 0 (erc-channel-user-status u)))
+      (should-not (erc-channel-user-voice u))
+      (should (eq t (setf (erc-channel-user-voice u) t)))
+      (should (eq t (erc-channel-user-voice u))))
+
+    (ert-info ("Add op status to user")
+      (should (= 1 (erc-channel-user-status u)))
+      (should-not (erc-channel-user-op u))
+      (should (eq t (setf (erc-channel-user-op u) t)))
+      (should (eq t (erc-channel-user-op u))))
+
+    (ert-info ("Add owner status to user")
+      (should (= 5 (erc-channel-user-status u)))
+      (should-not (erc-channel-user-owner u))
+      (should (eq t (setf (erc-channel-user-owner u) t)))
+      (should (eq t (erc-channel-user-owner u))))
+
+    (ert-info ("Remove owner status from user")
+      (should (= 21 (erc-channel-user-status u)))
+      (should-not (setf (erc-channel-user-owner u) nil))
+      (should-not (erc-channel-user-owner u)))
+
+    (ert-info ("Remove op status from user")
+      (should (= 5 (erc-channel-user-status u)))
+      (should-not (setf (erc-channel-user-op u) nil))
+      (should-not (erc-channel-user-op u)))
+
+    (ert-info ("Remove voice status from user")
+      (should (= 1 (erc-channel-user-status u)))
+      (should-not (setf (erc-channel-user-voice u) nil))
+      (should-not (erc-channel-user-voice u)))
+
+    (ert-info ("Remove voice status from zeroed user")
+      (should (= 0 (erc-channel-user-status u)))
+      (should-not (setf (erc-channel-user-voice u) nil))
+      (should-not (erc-channel-user-voice u))
+      (should (= 0 (erc-channel-user-status u))))))
+
 (defconst erc-tests--modules
   '( autoaway autojoin bufbar button capab-identify
      command-indicator completion dcc fill identd
@@ -2918,7 +3163,7 @@
     (while (accept-process-output proc 10))
     (goto-char (point-min))
     (unless (equal (read (current-buffer)) expected)
-      (message "Exepcted: %S\nGot: %s" expected (buffer-string))
+      (message "Expected: %S\nGot: %s" expected (buffer-string))
       (ert-fail "Mismatch"))))
 
 ;; Worrying about which library a module comes from is mostly not
@@ -3262,4 +3507,113 @@ connection."
                       (put 'erc-mname-enable 'definition-name 'mname)
                       (put 'erc-mname-disable 'definition-name 'mname))))))
 
+(defun erc-tests--string-to-propertized-parts (string)
+  "Return a sequence of `propertize' forms for generating STRING.
+Expect maintainers manipulating template catalogs to use this
+with `pp-eval-last-sexp' or similar to convert back and forth
+between literal strings."
+  `(concat
+    ,@(mapcar
+       (pcase-lambda (`(,beg ,end ,plist))
+         ;; At the time of writing, `propertize' produces a string
+         ;; with the order of the input plist reversed.
+         `(propertize ,(substring-no-properties string beg end)
+                      ,@(let (out)
+                          (while-let ((plist)
+                                      (k (pop plist))
+                                      (v (pop plist)))
+                            (push (if (or (consp v) (symbolp v)) `',v v) out)
+                            (push `',k out))
+                          out)))
+       (object-intervals string))))
+
+(defun erc-tests-pp-propertized-parts (arg)
+  "Convert literal string before point into a `propertize'd form.
+For simplicity, assume string evaluates to itself."
+  (interactive "P")
+  (let ((sexp (erc-tests--string-to-propertized-parts (pp-last-sexp))))
+    (if arg (insert (pp-to-string sexp)) (pp-eval-expression sexp))))
+
+(ert-deftest erc-tests--string-to-propertized-parts ()
+  :tags '(:unstable) ; only run this locally
+  (unless (>= emacs-major-version 28) (ert-skip "Missing `object-intervals'"))
+
+  (should (equal (erc-tests--string-to-propertized-parts
+                  #("abc"
+                    0 1 (face default foo 1)
+                    1 3 (face (default italic) bar "2")))
+                 '(concat (propertize "a" 'foo 1 'face 'default)
+                          (propertize "bc" 'bar "2" 'face '(default italic)))))
+  (should (equal #("abc"
+                   0 1 (face default foo 1)
+                   1 3 (face (default italic) bar "2"))
+                 (concat (propertize "a" 'foo 1 'face 'default)
+                         (propertize "bc" 'bar "2" 'face '(default italic))))))
+
+(ert-deftest erc--make-message-variable-name ()
+  (should (erc--make-message-variable-name 'english 'QUIT 'softp))
+  (should (erc--make-message-variable-name 'english 'QUIT nil))
+
+  (let ((obarray (obarray-make)))
+    (should-not (erc--make-message-variable-name 'testcat 'testkey 'softp))
+    (should (erc--make-message-variable-name 'testcat 'testkey nil))
+    (should (intern-soft "erc-message-testcat-testkey" obarray))
+    (should-not (erc--make-message-variable-name 'testcat 'testkey 'softp))
+    (set (intern "erc-message-testcat-testkey" obarray) "hello world")
+    (should (equal (symbol-value
+                    (erc--make-message-variable-name 'testcat 'testkey nil))
+                   "hello world")))
+
+  ;; Hyphenated (internal catalog).
+  (let ((obarray (obarray-make)))
+    (should-not (erc--make-message-variable-name '-testcat 'testkey 'softp))
+    (should (erc--make-message-variable-name '-testcat 'testkey nil))
+    (should (intern-soft "erc--message-testcat-testkey" obarray))
+    (should-not (erc--make-message-variable-name '-testcat 'testkey 'softp))
+    (set (intern "erc--message-testcat-testkey" obarray) "hello world")
+    (should (equal (symbol-value
+                    (erc--make-message-variable-name '-testcat 'testkey nil))
+                   "hello world"))))
+
+(ert-deftest erc-retrieve-catalog-entry ()
+  (should (eq 'english erc-current-message-catalog))
+  (should (equal (erc-retrieve-catalog-entry 's221) "User modes for %n: %m"))
+
+  ;; Local binding.
+  (with-temp-buffer
+    (should (equal (erc-retrieve-catalog-entry 's221) "User modes for %n: %m"))
+    (setq erc-current-message-catalog 'test)
+    ;; No catalog named `test'.
+    (should (equal (erc-retrieve-catalog-entry 's221) "User modes for %n: %m"))
+
+    (let ((obarray (obarray-make)))
+      (set (intern "erc-message-test-s221") "test 221 val")
+      (should (equal (erc-retrieve-catalog-entry 's221) "test 221 val"))
+      (set (intern "erc-message-english-s221") "eng 221 val")
+
+      (let ((erc-current-message-catalog 'english))
+        (should (equal (erc-retrieve-catalog-entry 's221) "eng 221 val")))
+
+      (with-temp-buffer
+        (should (equal (erc-retrieve-catalog-entry 's221) "eng 221 val"))
+        (let ((erc-current-message-catalog 'test))
+          (should (equal (erc-retrieve-catalog-entry 's221) "test 221 val"))))
+
+      (should (equal (erc-retrieve-catalog-entry 's221) "test 221 val")))
+
+    (should (equal (erc-retrieve-catalog-entry 's221) "User modes for %n: %m"))
+    (should (equal erc-current-message-catalog 'test)))
+
+  ;; Default top-level value.
+  (set-default-toplevel-value 'erc-current-message-catalog 'test-top)
+  (should (equal (erc-retrieve-catalog-entry 's221) "User modes for %n: %m"))
+  (set (intern "erc-message-test-top-s221") "test-top 221 val")
+  (should (equal (erc-retrieve-catalog-entry 's221) "test-top 221 val"))
+
+  (setq erc-current-message-catalog 'test-local)
+  (should (equal (erc-retrieve-catalog-entry 's221) "test-top 221 val"))
+
+  (makunbound (intern "erc-message-test-top-s221"))
+  (unintern "erc-message-test-top-s221" obarray))
+
 ;;; erc-tests.el ends here
diff --git a/test/lisp/erc/erc-track-tests.el b/test/lisp/erc/erc-track-tests.el
index ab8d708b721..ed3d190928f 100644
--- a/test/lisp/erc/erc-track-tests.el
+++ b/test/lisp/erc/erc-track-tests.el
@@ -104,6 +104,42 @@
                                       '("#emacs" "#vi"))
             '("#e" "#v"))) ))
 
+(ert-deftest erc-track--shortened-names ()
+  (let (erc-track--shortened-names
+        erc-track--shortened-names-current-hash
+        results)
+
+    (with-memoization (erc-track--shortened-names-get
+                       '("apple" "banana" "cherries"))
+      '("a" "b" "c"))
+    (should (integerp (car erc-track--shortened-names)))
+    (should (equal (cdr erc-track--shortened-names) '("a" "b" "c")))
+    (push erc-track--shortened-names results)
+
+    ;; Redundant call doesn't run.
+    (with-memoization (erc-track--shortened-names-get
+                       '("apple" "banana" "cherries"))
+      (should-not 'run)
+      '("a" "b" "c"))
+    (should (equal erc-track--shortened-names (car results)))
+
+    ;; Change in environment or context forces run.
+    (with-temp-buffer
+      (with-memoization (erc-track--shortened-names-get
+                         '("apple" "banana" "cherries"))
+        '("x" "y" "z")))
+    (should (and (integerp (car erc-track--shortened-names))
+                 (/= (car erc-track--shortened-names) (caar results))))
+    (should (equal (cdr erc-track--shortened-names) '("x" "y" "z")))
+    (push erc-track--shortened-names results)
+
+    (with-memoization (erc-track--shortened-names-get
+                       '("apple" "banana" "cherries"))
+      '("1" "2" "3"))
+    (should (and (integerp (car erc-track--shortened-names))
+                 (/= (car erc-track--shortened-names) (caar results))))
+    (should (equal (cdr erc-track--shortened-names) '("1" "2" "3")))))
+
 (ert-deftest erc-track--erc-faces-in ()
   "`erc-faces-in' should pick up both 'face and 'font-lock-face properties."
   (let ((str0 (copy-sequence "is bold"))
@@ -120,4 +156,134 @@
     (should (erc-faces-in str0))
     (should (erc-faces-in str1)) ))
 
+;; This simulates an alternating bold/non-bold [#c] in the mode-line,
+;; i.e., an `erc-modified-channels-alist' that vacillates between
+;;
+;;   ((#<buffer #chan> 42 . erc-default-face))
+;;
+;; and
+;;
+;;   ((#<buffer #chan> 42 erc-nick-default-face erc-default-face))
+;;
+;; This is a fairly typical scenario where consecutive messages
+;; feature speaker and addressee button highlighting and otherwise
+;; plain message bodies.  This mapping of phony to real faces
+;; describes the picture in 5.6:
+;;
+;;   `1': (erc-button erc-default-face)                 ; URL
+;;   `2': (erc-nick-default-face erc-default-face)      ; mention
+;;   `3': erc-default-face                              ; body
+;;   `_': (erc-nick-default-face erc-nick-default-face) ; speaker
+;;
+;; The `_' represents a commonly occurring face (a <speaker>) that's
+;; not present in either option's default (standard) value.  It's a
+;; no-op from the POV of `erc-track-select-mode-line-face'.
+
+(ert-deftest erc-track-select-mode-line-face ()
+
+  ;; Observed (see key above).
+  (let ((erc-track-faces-priority-list '(1 2 3))
+        (erc-track-faces-normal-list   '(1 2 3)))
+
+    (should (equal 2 (erc-track-select-mode-line-face 3 '(2 _ 3))))
+    (should (equal 2 (erc-track-select-mode-line-face 2 '(2 _ 3))))
+    (should (equal 3 (erc-track-select-mode-line-face 2 '(_ 3))))
+    (should (equal 2 (erc-track-select-mode-line-face 3 '(2 3))))
+    (should (equal 3 (erc-track-select-mode-line-face 2 '(3))))
+
+    (should (equal 1 (erc-track-select-mode-line-face 1 '(2 1 3))))
+    (should (equal 1 (erc-track-select-mode-line-face 1 '(1 3))))
+    (should (equal 1 (erc-track-select-mode-line-face 1 '(1 3 2))))
+    (should (equal 1 (erc-track-select-mode-line-face 1 '(3 1)))))
+
+  ;; When the current face outranks all new faces and doesn't appear
+  ;; among them, it's eligible to be replaced with a fellow "normal"
+  ;; from those new faces.  But if it does appear among them, it's
+  ;; never replaced.
+  (let ((erc-track-faces-priority-list '(a b))
+        (erc-track-faces-normal-list   '(a b)))
+
+    (should (equal 'a (erc-track-select-mode-line-face 'a '(b a))))
+    (should (equal 'a (erc-track-select-mode-line-face 'a '(a b))))
+    (should (equal 'a (erc-track-select-mode-line-face 'b '(b a))))
+    (should (equal 'a (erc-track-select-mode-line-face 'b '(a b))))
+
+    (should (equal 'a (erc-track-select-mode-line-face 'b '(a))))
+    (should (equal 'b (erc-track-select-mode-line-face 'a '(b)))))
+
+  ;; The ordering of the "normal" list doesn't matter.
+  (let ((erc-track-faces-priority-list '(a b))
+        (erc-track-faces-normal-list   '(b a)))
+
+    (should (equal 'a (erc-track-select-mode-line-face 'a '(b a))))
+    (should (equal 'a (erc-track-select-mode-line-face 'a '(a b))))
+    (should (equal 'a (erc-track-select-mode-line-face 'b '(b a))))
+    (should (equal 'a (erc-track-select-mode-line-face 'b '(a b))))))
+
+(defun erc-track-tests--select-mode-line-face (ranked normals cases)
+  (setq normals (map-into (mapcar (lambda (f) (cons f t)) normals)
+                          '(hash-table :test equal)))
+  (pcase-dolist (`(,want ,cur-face ,new-faces) cases)
+
+    (ert-info ((format "Observed: {cur: %S, new: %S, want: %S}"
+                       cur-face new-faces want))
+      (setq new-faces (cons (map-into
+                             (mapcar (lambda (f) (cons f t)) new-faces)
+                             '(hash-table :test equal))
+                            (reverse new-faces)))
+      (should (equal want (funcall #'erc-track--select-mode-line-face
+                                   cur-face new-faces ranked normals))))))
+
+;; The main difference between these variants is that with the above,
+;; when given alternating lines like
+;;
+;;  CUR      NEW                          CHOICE
+;;   text     (mention $speaker text)  =>   mention
+;;   mention  ($speaker text)          =>   text
+;;
+;; we see the effect of alternating faces in the indicator.  But when
+;; given consecutive lines with a similar composition, like
+;;
+;;   text     (mention $speaker text)  =>   mention
+;;   text     (mention $speaker text)  =>   mention
+;;
+;; we lose the effect.  With the variant below, we get
+;;
+;;   text     (mention $speaker text)  =>   mention
+;;   text     (mention $speaker text)  =>   text
+;;
+
+(ert-deftest erc-track--select-mode-line-face ()
+  (should-not erc-track-ignore-normal-contenders-p)
+
+  ;; These are the same test cases from the previous test.  The syntax
+  ;; is (expected cur-face new-faces).
+  (erc-track-tests--select-mode-line-face
+   '(1 2 3) '(1 2 3)
+   '((2 3 (2 _ 3))
+     (3 2 (2 _ 3))
+     (3 2 (_ 3))
+     (2 3 (2 3))
+     (3 2 (3))
+     (2 1 (2 1 3))
+     (3 1 (1 3))
+     (2 1 (1 3 2))
+     (3 1 (3 1))))
+
+  (erc-track-tests--select-mode-line-face
+   '(a b) '(a b)
+   '((b a (b a))
+     (b a (a b))
+     (a b (b a))
+     (a b (a b))
+     (a b (a))
+     (b a (b))))
+
+  (erc-track-tests--select-mode-line-face
+   '(a b) '(b a)
+   '((b a (b a))
+     (b a (a b))
+     (a b (b a))
+     (a b (a b)))))
+
 ;;; erc-track-tests.el ends here
diff --git a/test/lisp/erc/resources/base/display-message/statusmsg.eld 
b/test/lisp/erc/resources/base/display-message/statusmsg.eld
new file mode 100644
index 00000000000..7c42117080c
--- /dev/null
+++ b/test/lisp/erc/resources/base/display-message/statusmsg.eld
@@ -0,0 +1,47 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 10 "USER tester 0 * :tester")
+ (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.02 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version ergo-v2.11.1")
+ (0.01 ":irc.foonet.org 003 tester :This server was created Thu, 07 Dec 2023 
08:04:35 UTC")
+ (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.11.1 BERTZios 
CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0.00 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
CHATHISTORY=1000 ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX :are supported by 
this server")
+ (0.01 ":irc.foonet.org 005 tester KICKLEN=390 MAXLIST=beI:60 MAXTARGETS=4 
MODES MONITOR=100 NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=1000 :are supported by 
this server")
+ (0.00 ":irc.foonet.org 251 tester :There are 0 users and 4 invisible on 1 
server(s)")
+ (0.00 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0.00 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0.00 ":irc.foonet.org 254 tester 2 :channels formed")
+ (0.00 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0.02 ":irc.foonet.org 265 tester 4 5 :Current local users 4, max 5")
+ (0.00 ":irc.foonet.org 266 tester 4 5 :Current global users 4, max 5")
+ (0.00 ":irc.foonet.org 422 tester :MOTD File is missing")
+ (0.00 ":irc.foonet.org 221 tester +i")
+ (0.00 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((mode-tester 10 "MODE tester +i"))
+
+((join-mine 10 "JOIN #mine")
+ (0.01 ":irc.foonet.org 221 tester +i")
+ (0.00 ":tester!~u@2jv6nwu4af69s.irc JOIN #mine")
+ (0.02 ":irc.foonet.org 353 tester = #mine :@tester +dummy")
+ (0.01 ":irc.foonet.org 366 tester #mine :End of NAMES list"))
+
+((mode-mine 10 "MODE #mine")
+ (0.00 ":irc.foonet.org 324 tester #mine +Cnt")
+ (0.02 ":irc.foonet.org 329 tester #mine 1702026418")
+ (0.04 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :hello")
+ (0.03 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :there")
+ (0.05 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :\1ACTION sad\1")
+ (0.03 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :\1ACTION glad\1"))
+
+((privmsg-statusmsg 10 "PRIVMSG +#mine :howdy"))
+((privmsg-statusmsg-action 10 "PRIVMSG +#mine :tenderfoot")
+ ;; These are simulated "echoed messages"
+ (0.05 ":tester!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :\1ACTION mad\1")
+ (0.05 ":tester!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :\1ACTION chad\1"))
+
+((privmsg-prefixed 10 "PRIVMSG #mine :\1ACTION ready\1")
+ (0.04 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :okie")
+ (0.05 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG +#mine :\1ACTION dokie\1")
+ (0.04 ":dummy!~u@2jv6nwu4af69s.irc PRIVMSG #mine :\1ACTION out\1"))
diff --git a/test/lisp/erc/resources/commands/vhost.eld 
b/test/lisp/erc/resources/commands/vhost.eld
new file mode 100644
index 00000000000..42013198fbc
--- /dev/null
+++ b/test/lisp/erc/resources/commands/vhost.eld
@@ -0,0 +1,40 @@
+;; -*- mode: lisp-data; -*-
+((pass 10 "PASS :changeme"))
+((nick 10 "NICK tester"))
+((user 10 "USER user 0 * :tester")
+ (0 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running version 
oragono-2.6.0-7481bf0385b95b16")
+ (0 ":irc.foonet.org 003 tester :This server was created Tue, 04 May 2021 
05:06:18 UTC")
+ (0 ":irc.foonet.org 004 tester irc.foonet.org oragono-2.6.0-7481bf0385b95b16 
BERTZios CEIMRUabefhiklmnoqstuv Iabefhkloqv")
+ (0 ":irc.foonet.org 005 tester AWAYLEN=390 BOT=B CASEMAPPING=ascii 
CHANLIMIT=#:100 CHANMODES=Ibe,k,fl,CEMRUimnstu CHANNELLEN=64 CHANTYPES=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0 ":irc.foonet.org 005 tester MAXLIST=beI:60 MAXTARGETS=4 MODES MONITOR=100 
NETWORK=foonet NICKLEN=32 PREFIX=(qaohv)~&@%+ STATUSMSG=~&@%+ 
TARGMAX=NAMES:1,LIST:1,KICK:1,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :are supported by this 
server")
+ (0 ":irc.foonet.org 251 tester :There are 0 users and 3 invisible on 1 
server(s)")
+ (0 ":irc.foonet.org 252 tester 0 :IRC Operators online")
+ (0 ":irc.foonet.org 253 tester 0 :unregistered connections")
+ (0 ":irc.foonet.org 254 tester 1 :channels formed")
+ (0 ":irc.foonet.org 255 tester :I have 3 clients and 0 servers")
+ (0 ":irc.foonet.org 265 tester 3 3 :Current local users 3, max 3")
+ (0 ":irc.foonet.org 266 tester 3 3 :Current global users 3, max 3")
+ (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode-user 10 "MODE tester +i")
+ (0 ":irc.foonet.org 221 tester +i")
+ (0 ":irc.foonet.org NOTICE tester :This server is in debug mode and is 
logging all user I/O. If you do not wish for everything you send to be readable 
by the server owner(s), please disconnect."))
+
+((join 10 "JOIN #chan")
+ (0 ":tester!~u@9g6b728983yd2.irc JOIN #chan")
+ (0 ":irc.foonet.org 353 tester = #chan :alice tester @bob")
+ (0 ":irc.foonet.org 366 tester #chan :End of NAMES list"))
+
+((mode-chan 10 "MODE #chan")
+ (0 ":irc.foonet.org 324 tester #chan +nt")
+ (0 ":irc.foonet.org 329 tester #chan 1620104779")
+ (0 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!")
+ (0 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :tester, welcome!"))
+
+((vhost 10 "VHOST tester changeme")
+ (0 ":irc.foonet.org NOTICE tester :Setting your VHost: some.host.test.cc")
+ (0 ":irc.foonet.org 396 tester some.host.test.cc :is now your displayed host")
+ (0 ":bob!~u@rz2v467q4rwhy.irc PRIVMSG #chan :alice: But, as it seems, did 
violence on herself.")
+ (0 ":alice!~u@rz2v467q4rwhy.irc PRIVMSG #chan :bob: Well, this is the forest 
of Arden."))
diff --git a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld 
b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld
index c07eee3517f..3c32719a052 100644
--- a/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld
+++ b/test/lisp/erc/resources/fill/snapshots/merge-01-start.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<alic [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<alic [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld 
b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld
index cf5cdb4f825..e2064b914c4 100644
--- a/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld
+++ b/test/lisp/erc/resources/fill/snapshots/merge-02-right.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<alic [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<alic [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld 
b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld
index ad4e6483f01..feaba85ec90 100644
--- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld
+++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-01.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<bob> [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<bob> [...]
\ No newline at end of file
diff --git 
a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld 
b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld
index 893588c028f..ed1488c8595 100644
--- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld
+++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-post-01.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<bob> [...]
\ No newline at end of file
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<bob> [...]
\ No newline at end of file
diff --git 
a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld 
b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld
index 2b67cbbf90e..a3530a6c44d 100644
--- a/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld
+++ b/test/lisp/erc/resources/fill/snapshots/merge-wrap-indicator-pre-01.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<bob> [...]
\ No newline at end of file
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n\n[Sat Apr  1 
2023]\n<bob> zero.[07:00]\n<bob> [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld 
b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld
index 84a1e34670c..c94629cf357 100644
--- a/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld
+++ b/test/lisp/erc/resources/fill/snapshots/monospace-01-start.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc-msg 
datestamp erc-ts 0 field erc-ti [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg 
datestamp erc--ts 0 field erc- [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld 
b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld
index 83394f2f639..127c0b29bc9 100644
--- a/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld
+++ b/test/lisp/erc/resources/fill/snapshots/monospace-02-right.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc-msg 
datestamp erc-ts 0 field erc-ti [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg 
datestamp erc--ts 0 field erc- [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld 
b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld
index 1605628b29f..a9f3f1d1904 100644
--- a/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld
+++ b/test/lisp/erc/resources/fill/snapshots/monospace-03-left.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc-msg 
datestamp erc-ts 0 field erc-ti [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg 
datestamp erc--ts 0 field erc- [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld 
b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld
index 84a1e34670c..c94629cf357 100644
--- a/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld
+++ b/test/lisp/erc/resources/fill/snapshots/monospace-04-reset.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc-msg 
datestamp erc-ts 0 field erc-ti [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg 
datestamp erc--ts 0 field erc- [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld 
b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld
index 7a7e01de49d..754d7989cea 100644
--- a/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld
+++ b/test/lisp/erc/resources/fill/snapshots/spacing-01-mono.eld
@@ -1 +1 @@
-#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n<bob> This 
buffer is for text.\n*** one two th [...]
+#("\n\n\n[Thu Jan  1 1970]\n*** This server is in debug mode and is logging 
all user I/O. If you do not wish for everything you send to be readable by the 
server owner(s), please disconnect.[00:00]\n<alice> bob: come, you are a 
tedious fool: to the purpose. What was done to Elbow's wife, that he hath cause 
to complain of? Come me to what was done to her.\n<bob> alice: Either your 
unparagoned mistress is dead, or she's outprized by a trifle.\n<bob> This 
buffer is for text.\n*** one two th [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld 
b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld
index bb248ffb28e..1b22b6c5cfd 100644
--- a/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld
+++ b/test/lisp/erc/resources/fill/snapshots/stamps-left-01.eld
@@ -1 +1 @@
-#("\n\n[00:00]*** This server is in debug mode and is logging all user I/O. If 
you do not wish for everything you send to be readable by the server owner(s), 
please disconnect.\n[00:00]<alice> bob: come, you are a tedious fool: to the 
purpose. What was done to Elbow's wife, that he hath cause to complain of? Come 
me to what was done to her.\n[00:00]<bob> alice: Either your unparagoned 
mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc-msg notice erc-ts 
0 display #3=(#5=(margin [...]
+#("\n\n[00:00]*** This server is in debug mode and is logging all user I/O. If 
you do not wish for everything you send to be readable by the server owner(s), 
please disconnect.\n[00:00]<alice> bob: come, you are a tedious fool: to the 
purpose. What was done to Elbow's wife, that he hath cause to complain of? Come 
me to what was done to her.\n[00:00]<bob> alice: Either your unparagoned 
mistress is dead, or she's outprized by a trifle.\n" 2 3 (erc--msg notice 
erc--ts 0 display #3=(#5=(marg [...]
\ No newline at end of file
diff --git a/test/lisp/erc/resources/join/network-id/foonet-again.eld 
b/test/lisp/erc/resources/join/network-id/foonet-again.eld
index b230eff27c7..a8b8a52f87a 100644
--- a/test/lisp/erc/resources/join/network-id/foonet-again.eld
+++ b/test/lisp/erc/resources/join/network-id/foonet-again.eld
@@ -43,4 +43,4 @@
  (0.1 ":bob!~u@q6ddatxcq6txy.irc PRIVMSG #chan :alice: But we are spirits of 
another sort.")
  (0.1 ":alice!~u@q6ddatxcq6txy.irc PRIVMSG #chan :bob: It was not given me, 
nor I did not buy it."))
 
-((linger 6 LINGER))
+((linger 30 LINGER))
diff --git a/test/lisp/eshell/em-hist-tests.el 
b/test/lisp/eshell/em-hist-tests.el
index 466d19cc6f7..078bcb490e5 100644
--- a/test/lisp/eshell/em-hist-tests.el
+++ b/test/lisp/eshell/em-hist-tests.el
@@ -35,7 +35,7 @@
 (cl-defun em-hist-test/check-history-file (file-name expected &optional
                                                      (expected-ring t))
   "Check that the contents of FILE-NAME match the EXPECTED history entries.
-Additonally, check that after loading the file, the history ring
+Additionally, check that after loading the file, the history ring
 matches too.  If EXPECTED-RING is a list, compare the ring
 elements against that; if t (the default), check against EXPECTED."
   (when (eq expected-ring t) (setq expected-ring expected))
diff --git a/test/lisp/eshell/esh-io-tests.el b/test/lisp/eshell/esh-io-tests.el
index 0201b6ab650..bc3d9c6e5d5 100644
--- a/test/lisp/eshell/esh-io-tests.el
+++ b/test/lisp/eshell/esh-io-tests.el
@@ -328,7 +328,7 @@ stdout originally pointed (the terminal)."
                                "tuodts\nrredts\n"))
 
 (ert-deftest esh-io-test/pipeline/subcommands ()
-  "Chek that all commands in a subcommand are properly piped."
+  "Check that all commands in a subcommand are properly piped."
   (skip-unless (executable-find "rev"))
   (with-temp-eshell
    (eshell-match-command-output "{echo foo; echo bar} | rev"
diff --git a/test/lisp/files-x-tests.el b/test/lisp/files-x-tests.el
index 4e14ae68fb8..c7a56611497 100644
--- a/test/lisp/files-x-tests.el
+++ b/test/lisp/files-x-tests.el
@@ -39,6 +39,7 @@
 (defconst files-x-test--variables5
   '((remote-lazy-var . nil)
     (remote-null-device . "/dev/null")))
+(defvar remote-shell-file-name)
 (defvar remote-null-device)
 (defvar remote-lazy-var nil)
 (put 'remote-shell-file-name 'safe-local-variable #'identity)
@@ -482,5 +483,80 @@ If it's not initialized yet, initialize it."
      `(connection-local-profile-alist ',clpa now)
      `(connection-local-criteria-alist ',clca now))))
 
+(ert-deftest files-x-test-connection-local-value ()
+  "Test getting connection-local values."
+
+  (let ((clpa connection-local-profile-alist)
+       (clca connection-local-criteria-alist))
+    (connection-local-set-profile-variables
+     'remote-bash files-x-test--variables1)
+    (connection-local-set-profile-variables
+     'remote-ksh files-x-test--variables2)
+    (connection-local-set-profile-variables
+     'remote-nullfile files-x-test--variables3)
+
+    (connection-local-set-profiles
+     nil 'remote-ksh 'remote-nullfile)
+
+    (connection-local-set-profile-variables
+     'remote-lazy files-x-test--variables5)
+    (connection-local-set-profiles
+     files-x-test--application 'remote-lazy 'remote-bash)
+
+    (with-temp-buffer
+      ;; We need a remote `default-directory'.
+      (let ((enable-connection-local-variables t)
+           (default-directory "/method:host:")
+           (remote-null-device "null"))
+        (should-not connection-local-variables-alist)
+        (should-not (local-variable-p 'remote-shell-file-name))
+        (should-not (local-variable-p 'remote-null-device))
+        (should-not (boundp 'remote-shell-file-name))
+        (should (string-equal (symbol-value 'remote-null-device) "null"))
+
+        ;; The proper variable values are set.
+        (should (connection-local-p remote-shell-file-name))
+        (should
+         (string-equal
+          (connection-local-value remote-shell-file-name) "/bin/ksh"))
+        (should (connection-local-p remote-null-device))
+        (should
+         (string-equal
+          (connection-local-value remote-null-device) "/dev/null"))
+        (should-not (connection-local-p remote-lazy-var))
+
+        ;; Run with a different application.
+        (should
+         (connection-local-p
+          remote-shell-file-name (cadr files-x-test--application)))
+        (should
+         (string-equal
+          (connection-local-value
+           remote-shell-file-name (cadr files-x-test--application))
+          "/bin/bash"))
+        (should
+         (connection-local-p
+          remote-null-device (cadr files-x-test--application)))
+        (should
+         (string-equal
+          (connection-local-value
+           remote-null-device (cadr files-x-test--application))
+          "/dev/null"))
+        (should
+         (connection-local-p
+          remote-lazy-var (cadr files-x-test--application)))
+
+        ;; The previous bindings haven't changed.
+        (should-not connection-local-variables-alist)
+        (should-not (local-variable-p 'remote-shell-file-name))
+        (should-not (local-variable-p 'remote-null-device))
+        (should-not (boundp 'remote-shell-file-name))
+        (should (string-equal (symbol-value 'remote-null-device) "null"))))
+
+    ;; Cleanup.
+    (custom-set-variables
+     `(connection-local-profile-alist ',clpa now)
+     `(connection-local-criteria-alist ',clca now))))
+
 (provide 'files-x-tests)
 ;;; files-x-tests.el ends here
diff --git a/test/lisp/international/mule-tests.el 
b/test/lisp/international/mule-tests.el
index 4dc099a18af..c973955e4ce 100644
--- a/test/lisp/international/mule-tests.el
+++ b/test/lisp/international/mule-tests.el
@@ -49,7 +49,7 @@
                        (kbd "C-x RET c u t f - 8 RET C-u C-u c a b RET")
                      (read-string "prompt:"))))))
 
-;;Bug#65997, ensure that old-names haven't overriden new names.
+;;Bug#65997, ensure that old-names haven't overridden new names.
 (ert-deftest mule-cmds-tests--ucs-names-old-name-override ()
   (let (code-points)
     (dotimes (u (1+ (max-char 'ucs)))
diff --git a/test/lisp/jsonrpc-tests.el b/test/lisp/jsonrpc-tests.el
index 85ac96a931c..5c3b694194f 100644
--- a/test/lisp/jsonrpc-tests.el
+++ b/test/lisp/jsonrpc-tests.el
@@ -103,6 +103,7 @@
                         (process-get listen-server 'handlers))))))))
 
 (cl-defmacro jsonrpc--with-emacsrpc-fixture ((endpoint-sym) &body body)
+  (declare (indent 1))
   `(jsonrpc--call-with-emacsrpc-fixture (lambda (,endpoint-sym) ,@body)))
 
 (ert-deftest returns-3 ()
@@ -151,14 +152,6 @@
              [1 2 3 3 4 5]
              (jsonrpc-request conn 'vconcat [[1 2 3] [3 4 5]])))))
 
-(ert-deftest json-el-cant-serialize-this ()
-  "Can't serialize a response that is half-vector/half-list."
-  (jsonrpc--with-emacsrpc-fixture (conn)
-                                  (should-error
-                                   ;; (append [1 2 3] [3 4 5]) => (1 2 3 . [3 
4 5]), which can't be
-                                   ;; serialized
-                                   (jsonrpc-request conn 'append [[1 2 3] [3 4 
5]]))))
-
 (cl-defmethod jsonrpc-connection-ready-p
   ((conn jsonrpc--test-client) what)
   (and (cl-call-next-method)
diff --git a/test/lisp/net/tramp-tests.el b/test/lisp/net/tramp-tests.el
index d8932a28e4d..68bf928eb62 100644
--- a/test/lisp/net/tramp-tests.el
+++ b/test/lisp/net/tramp-tests.el
@@ -3811,7 +3811,7 @@ This tests also `access-file', `file-readable-p',
            (should (eq (file-attribute-type attr) t)))
 
        ;; Cleanup.
-       (ignore-errors (delete-directory tmp-name1))
+       (ignore-errors (delete-directory tmp-name1 'recursive))
        (ignore-errors (delete-file tmp-name1))
        (ignore-errors (delete-file tmp-name2))))))
 
@@ -6360,6 +6360,8 @@ INPUT, if non-nil, is a string sent to the process."
          (tramp-remote-path tramp-remote-path)
         (orig-tramp-remote-path tramp-remote-path)
         path)
+    ;; The "flatpak" method modifies `tramp-remote-path'.
+    (skip-unless (not (tramp-compat-connection-local-p tramp-remote-path)))
     (unwind-protect
        (progn
           ;; Non existing directories are removed.
diff --git a/test/lisp/proced-tests.el b/test/lisp/proced-tests.el
index 44596f92490..58d97f46c4f 100644
--- a/test/lisp/proced-tests.el
+++ b/test/lisp/proced-tests.el
@@ -46,7 +46,7 @@
   (move-to-column (string-match attribute proced-header-line)))
 
 (defun proced--assert-process-valid-pid-refinement (pid)
-  "Fail unless the process at point could be present after a refinment using 
PID."
+  "Fail unless the process at point could be present after a refinement using 
PID."
   (proced--move-to-column "PID")
   (let ((pid-equal (string= pid (word-at-point))))
     (should
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
index 74e34fe821b..fa65ba83a69 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent-bsd.erts
@@ -91,3 +91,37 @@ main (int   argc,
   }
 }
 =-=-=
+
+Name: Bracketless Simple Statement (bug#66152)
+
+=-=
+for (int i = 0; i < 5; i++)
+continue;
+
+while (true)
+return 1;
+
+do
+i++;
+while (true)
+
+if (true)
+break;
+else
+break;
+=-=
+for (int i = 0; i < 5; i++)
+  continue;
+
+while (true)
+  return 1;
+
+do
+  i++;
+while (true)
+
+if (true)
+  break;
+else
+  break;
+=-=-=
diff --git a/test/lisp/progmodes/c-ts-mode-resources/indent.erts 
b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
index bac76fb7378..2fd26d75844 100644
--- a/test/lisp/progmodes/c-ts-mode-resources/indent.erts
+++ b/test/lisp/progmodes/c-ts-mode-resources/indent.erts
@@ -330,7 +330,7 @@ label:
 
 Name: Bracket-less Block-Statement (Linux Style) (bug#61026)
 
-=-=-=
+=-=
 int main() {
   while (true)
     if (true) {
@@ -351,6 +351,8 @@ int main() {
     if (true) {
       puts ("Hello");
     }
+    else
+      puts("Hello");
 }
 =-=-=
 
@@ -399,6 +401,34 @@ void foo(
 }
 =-=-=
 
+Name: Block-Statement where first siblings are comments (Linux Style)
+
+=-=
+int main() {
+  while (true) { /* foo */
+    if (true) { // bar
+      puts ("Hello");
+    }
+  }
+  for (;;) {  // 1. fooo
+    /* 2. baaa */
+    /* 3. rrr */
+    if (true)
+      // 2. baaa
+      puts ("Hello");
+  }
+  if (1) { // 1
+    /*
+     * 2
+     */
+    if (1) /*3*/ {
+      /* 4 */
+      puts("Hello");
+    }
+  }
+}
+=-=-=
+
 Name: Initializer List (Linux Style) (Bug#61398)
 
 =-=
@@ -498,3 +528,19 @@ main (void)
 {
   |
 =-=-=
+
+Code:
+  (lambda ()
+    (c-ts-mode)
+    (setq-local indent-tabs-mode nil)
+    (goto-line 3)
+    (indent-for-tab-command))
+
+Name: Block-Statement where previous sibling is comment
+
+=-=
+int main() {
+    puts ("Hello"); // unusual indent and has trailing comment.
+    return true; // Should align with previous non-comment sibling (rather 
than one level up against parent).
+}
+=-=-=
diff --git a/test/lisp/progmodes/eglot-tests.el 
b/test/lisp/progmodes/eglot-tests.el
index 575a6ac8ef1..996ff276e68 100644
--- a/test/lisp/progmodes/eglot-tests.el
+++ b/test/lisp/progmodes/eglot-tests.el
@@ -209,27 +209,25 @@ directory hierarchy."
                                client-replies))
            (advice-add
             #'jsonrpc--log-event :before
-            (lambda (_proc message &optional type)
-              (cl-destructuring-bind (&key method id _error &allow-other-keys)
-                  message
-                (let ((req-p (and method id))
-                      (notif-p method)
-                      (reply-p id))
-                  (cond
-                   ((eq type 'server)
-                    (cond (req-p ,(when server-requests
-                                    `(push message ,server-requests)))
-                          (notif-p ,(when server-notifications
-                                      `(push message ,server-notifications)))
-                          (reply-p ,(when server-replies
-                                      `(push message ,server-replies)))))
-                   ((eq type 'client)
-                    (cond (req-p ,(when client-requests
-                                    `(push message ,client-requests)))
-                          (notif-p ,(when client-notifications
-                                      `(push message ,client-notifications)))
-                          (reply-p ,(when client-replies
-                                      `(push message ,client-replies)))))))))
+            (lambda (_proc message &optional origin subtype)
+              (let ((req-p (eq subtype 'request))
+                    (notif-p (eq subtype 'notification))
+                    (reply-p (eql subtype 'reply)))
+                (cond
+                 ((eq origin 'server)
+                  (cond (req-p ,(when server-requests
+                                  `(push message ,server-requests)))
+                        (notif-p ,(when server-notifications
+                                    `(push message ,server-notifications)))
+                        (reply-p ,(when server-replies
+                                    `(push message ,server-replies)))))
+                 ((eq origin 'client)
+                  (cond (req-p ,(when client-requests
+                                  `(push message ,client-requests)))
+                        (notif-p ,(when client-notifications
+                                    `(push message ,client-notifications)))
+                        (reply-p ,(when client-replies
+                                    `(push message ,client-replies))))))))
             '((name . ,log-event-ad-sym)))
            ,@body)
        (advice-remove #'jsonrpc--log-event ',log-event-ad-sym))))
diff --git a/test/lisp/progmodes/js-resources/js-ts-indents.erts 
b/test/lisp/progmodes/js-resources/js-ts-indents.erts
new file mode 100644
index 00000000000..2e34b23acef
--- /dev/null
+++ b/test/lisp/progmodes/js-resources/js-ts-indents.erts
@@ -0,0 +1,44 @@
+Code:
+  (lambda ()
+    (setq indent-tabs-mode nil)
+    (setq js-indent-level 2)
+    (js-ts-mode)
+    (indent-region (point-min) (point-max)))
+
+Name: Basic indentation
+
+=-=
+const foo = () => {
+  console.log("bar");
+  if (x) {
+    return y;
+  } else if (y) {
+    return u;
+  }
+  return baz.x()
+    ? true
+    : false;
+}
+=-=-=
+
+Name: Statement indentation without braces
+
+=-=
+function bracketless_statements(x) {
+  if (x == 0)
+    console.log("if_statement");
+  else if (x == 1)
+    console.log("if_statement");
+  else
+    console.log("else_clause");
+  for (let i = 0; i < 1; i++)
+    console.log("for_statement");
+  for (let _ of [true])
+    console.log("for_in_statement");
+  while (x-- > 0)
+    console.log("while_statement");
+  do
+    console.log("do_statement");
+  while (false)
+};
+=-=-=
diff --git a/test/lisp/progmodes/js-tests.el b/test/lisp/progmodes/js-tests.el
index 5db92b08f8a..827d7bb8a99 100644
--- a/test/lisp/progmodes/js-tests.el
+++ b/test/lisp/progmodes/js-tests.el
@@ -288,6 +288,12 @@ function bar() {
     ;; end-of-defun should move point to eob.
     (should (eobp))))
 
+;;;; Tree-sitter tests.
+
+(ert-deftest js-ts-mode-test-indentation ()
+  (skip-unless (treesit-ready-p 'javascript))
+  (ert-test-erts-file (ert-resource-file "js-ts-indents.erts")))
+
 (provide 'js-tests)
 
 ;;; js-tests.el ends here
diff --git a/test/lisp/progmodes/lua-ts-mode-resources/font-lock.lua 
b/test/lisp/progmodes/lua-ts-mode-resources/font-lock.lua
new file mode 100644
index 00000000000..93d589e3825
--- /dev/null
+++ b/test/lisp/progmodes/lua-ts-mode-resources/font-lock.lua
@@ -0,0 +1,339 @@
+#!/usr/bin/env lua
+-- ^ font-lock-comment-face
+-- Comment
+-- <- font-lock-comment-delimiter-face
+-- ^ font-lock-comment-face
+--[[
+-- ^ font-lock-comment-face
+Multi-line comment
+-- ^ font-lock-comment-face
+]]
+-- <- font-lock-comment-face
+local line_comment = "comment" -- comment
+--                                ^ font-lock-comment-face
+
+-- Definition
+local function f1() end
+--             ^ font-lock-function-name-face
+local f2 = function() end
+--    ^ font-lock-function-name-face
+local tb = { f1 = function() end }
+--           ^ font-lock-function-name-face
+function tb.f2() end
+--          ^ font-lock-function-name-face
+function tb:f3() end
+--          ^ font-lock-function-name-face
+tbl.f4 = function() end
+--  ^ font-lock-function-name-face
+function x.y:z() end
+--           ^ font-lock-function-name-face
+
+-- Keyword
+if true then
+-- <- font-lock-keyword-face
+--      ^ font-lock-keyword-face
+elseif true then
+-- <- font-lock-keyword-face
+else end
+-- <- font-lock-keyword-face
+--   ^ font-lock-keyword-face
+local p = {}
+-- ^ font-lock-keyword-face
+for k,v in pairs({}) do end
+-- <- font-lock-keyword-face
+--      ^ font-lock-keyword-face
+repeat if true then break end until false
+-- <- font-lock-keyword-face
+--                  ^ font-lock-keyword-face
+--                            ^ font-lock-keyword-face
+while true do end
+-- <- font-lock-keyword-face
+--         ^ font-lock-keyword-face
+function fn() return true end
+-- <- font-lock-keyword-face
+--            ^ font-lock-keyword-face
+goto label1
+-- ^ font-lock-keyword-face
+::label1::
+if true and not false or nil then
+--      ^ font-lock-keyword-face
+--          ^ font-lock-keyword-face
+--                    ^ font-lock-keyword-face
+end
+
+-- String
+local _
+_ = "x"
+--   ^ font-lock-string-face
+_ = 'x'
+--   ^ font-lock-string-face
+_ = "x\ty"
+--   ^ font-lock-string-face
+--      ^ font-lock-string-face
+_ = "x\"y"
+--   ^ font-lock-string-face
+--      ^ font-lock-string-face
+_ = 'x\'y'
+--   ^ font-lock-string-face
+--      ^ font-lock-string-face
+_ = "x\z
+    y"
+--  ^ font-lock-string-face
+_ = "x\0900y"
+--        ^ font-lock-string-face
+_ = "x\09y"
+--       ^ font-lock-string-face
+_ = "x\0y"
+--      ^ font-lock-string-face
+_ = "x\u{1f602}y"
+--             ^ font-lock-string-face
+_ = [[x]]
+--    ^ font-lock-string-face
+_ = [=[x]=]
+--     ^ font-lock-string-face
+
+-- Assignment
+local n = 0
+--    ^ font-lock-variable-name-face
+o, p, q = 1, 2, 3
+-- <- font-lock-variable-name-face
+-- ^ font-lock-variable-name-face
+--    ^ font-lock-variable-name-face
+tbl[k] = "A"
+--  ^ font-lock-variable-name-face
+tbl.x = 1
+--  ^ font-lock-variable-name-face
+for i=0,9 do end
+--  ^ font-lock-variable-name-face
+
+-- Constant
+local x <const> = 1
+--      ^ font-lock-constant-face
+local f <close> = io.open('/file')
+--      ^ font-lock-constant-face
+local a, b, c = true, false, nil
+--              ^ font-lock-constant-face
+--                    ^ font-lock-constant-face
+--                           ^ font-lock-constant-face
+::label2::
+-- ^ font-lock-constant-face
+goto label2
+--   ^ font-lock-constant-face
+
+-- Number
+n = 123
+--  ^ font-lock-number-face
+print(99)
+--    ^ font-lock-number-face
+print(tbl[1])
+--        ^ font-lock-number-face
+
+-- Bracket
+local t = {}
+--        ^ font-lock-bracket-face
+--         ^ font-lock-bracket-face
+print(t[1])
+--   ^ font-lock-bracket-face
+--     ^ font-lock-bracket-face
+--       ^ font-lock-bracket-face
+--        ^ font-lock-bracket-face
+
+-- Builtin
+assert()
+-- <- font-lock-builtin-face
+bit32()
+-- <- font-lock-builtin-face
+collectgarbage()
+-- <- font-lock-builtin-face
+coroutine()
+-- <- font-lock-builtin-face
+debug()
+-- <- font-lock-builtin-face
+dofile()
+-- <- font-lock-builtin-face
+error()
+-- <- font-lock-builtin-face
+getmetatable()
+-- <- font-lock-builtin-face
+io()
+-- <- font-lock-builtin-face
+ipairs()
+-- <- font-lock-builtin-face
+load()
+-- <- font-lock-builtin-face
+loadfile()
+-- <- font-lock-builtin-face
+math()
+-- <- font-lock-builtin-face
+next()
+-- <- font-lock-builtin-face
+os()
+-- <- font-lock-builtin-face
+package()
+-- <- font-lock-builtin-face
+pairs()
+-- <- font-lock-builtin-face
+pcall()
+-- <- font-lock-builtin-face
+print()
+-- <- font-lock-builtin-face
+rawequal()
+-- <- font-lock-builtin-face
+rawget()
+-- <- font-lock-builtin-face
+rawlen()
+-- <- font-lock-builtin-face
+rawset()
+-- <- font-lock-builtin-face
+require()
+-- <- font-lock-builtin-face
+select()
+-- <- font-lock-builtin-face
+setmetatable()
+-- <- font-lock-builtin-face
+string()
+-- <- font-lock-builtin-face
+table()
+-- <- font-lock-builtin-face
+tonumber()
+-- <- font-lock-builtin-face
+tostring()
+-- <- font-lock-builtin-face
+type()
+-- <- font-lock-builtin-face
+utf8()
+-- <- font-lock-builtin-face
+warn()
+-- <- font-lock-builtin-face
+xpcall()
+-- <- font-lock-builtin-face
+print(_G)
+--    ^ font-lock-builtin-face
+print(_VERSION)
+--    ^ font-lock-builtin-face
+f.close()
+-- ^ font-lock-builtin-face
+f.flush()
+-- ^ font-lock-builtin-face
+f.lines()
+-- ^ font-lock-builtin-face
+f.read()
+-- ^ font-lock-builtin-face
+f.seek()
+-- ^ font-lock-builtin-face
+f.setvbuf()
+-- ^ font-lock-builtin-face
+f.write()
+-- ^ font-lock-builtin-face
+
+-- Delimiter
+t = { 1, 2 };
+--     ^ font-lock-delimiter-face
+--          ^ font-lock-delimiter-face
+
+-- Escape
+_ = "x\ty"
+--    ^ font-lock-escape-face
+--     ^ font-lock-escape-face
+_ = "x\"y"
+--    ^ font-lock-escape-face
+--     ^ font-lock-escape-face
+_ = 'x\'y'
+--    ^ font-lock-escape-face
+--     ^ font-lock-escape-face
+_ = "x\z
+    y"
+-- <- font-lock-escape-face
+_ = "x\x5Ay"
+--     ^ font-lock-escape-face
+--      ^ font-lock-escape-face
+_ = "x\0900y"
+--       ^ font-lock-escape-face
+_ = "x\09y"
+--      ^ font-lock-escape-face
+_ = "x\0y"
+--     ^ font-lock-escape-face
+_ = "x\u{1f602}y"
+--     ^ font-lock-escape-face
+--         ^ font-lock-escape-face
+
+-- Function
+func_one()
+--  ^ font-lock-function-call-face
+tbl.func_two()
+--  ^ font-lock-function-call-face
+tbl:func_three()
+--  ^ font-lock-function-call-face
+tbl.f = f4()
+--      ^ font-lock-function-call-face
+
+-- Operator
+local a, b = 1, 2
+--         ^ font-lock-operator-face
+print(a & b)
+--      ^ font-lock-operator-face
+print(a | b)
+--      ^ font-lock-operator-face
+print(a ~ b)
+--      ^ font-lock-operator-face
+print(a << 1)
+--      ^ font-lock-operator-face
+--       ^ font-lock-operator-face
+print(a >> 1)
+--      ^ font-lock-operator-face
+--       ^ font-lock-operator-face
+print(a+b-a*b/a%b^a//b)
+--     ^ font-lock-operator-face
+--       ^ font-lock-operator-face
+--         ^ font-lock-operator-face
+--           ^ font-lock-operator-face
+--             ^ font-lock-operator-face
+--               ^ font-lock-operator-face
+--                 ^ font-lock-operator-face
+print(#t)
+--    ^ font-lock-operator-face
+print("h".."at")
+--       ^ font-lock-operator-face
+print(a==b)
+--     ^ font-lock-operator-face
+print(a~=b)
+--     ^ font-lock-operator-face
+print(a<=b)
+--     ^ font-lock-operator-face
+print(a>=b)
+--     ^ font-lock-operator-face
+print(a<b)
+--     ^ font-lock-operator-face
+print(a>b)
+--     ^ font-lock-operator-face
+function ff(...) end
+--          ^ font-lock-operator-face
+
+-- Property
+t = { a=1 }
+--    ^ font-lock-property-name-face
+print(t.a)
+--      ^ font-lock-property-use-face
+
+-- Punctuation
+tbl.f2()
+-- ^ font-lock-punctuation-face
+tbl:f3()
+-- ^ font-lock-punctuation-face
+
+-- Variable
+function fn(x, y) end
+--          ^ font-lock-variable-name-face
+--             ^ font-lock-variable-name-face
+fn(a, b)
+-- ^ font-lock-variable-use-face
+--    ^ font-lock-variable-use-face
+print(a + b)
+--    ^ font-lock-variable-use-face
+--        ^ font-lock-variable-use-face
+print(t[a])
+--      ^ font-lock-variable-use-face
+tbl.f1(p)
+--     ^ font-lock-variable-use-face
+tbl:f2(q)
+--     ^ font-lock-variable-use-face
diff --git a/test/lisp/progmodes/lua-ts-mode-tests.el 
b/test/lisp/progmodes/lua-ts-mode-tests.el
index d2105b66f6d..8a566d777e3 100644
--- a/test/lisp/progmodes/lua-ts-mode-tests.el
+++ b/test/lisp/progmodes/lua-ts-mode-tests.el
@@ -20,17 +20,23 @@
 ;;; Code:
 
 (require 'ert)
+(require 'ert-font-lock)
 (require 'ert-x)
 (require 'treesit)
 
-(ert-deftest lua-ts-mode-test-indentation ()
+(ert-deftest lua-ts-test-indentation ()
   (skip-unless (treesit-ready-p 'lua))
   (ert-test-erts-file (ert-resource-file "indent.erts")))
 
-(ert-deftest lua-ts-mode-test-movement ()
+(ert-deftest lua-ts-test-movement ()
   (skip-unless (treesit-ready-p 'lua))
   (ert-test-erts-file (ert-resource-file "movement.erts")))
 
+(ert-deftest lua-ts-test-font-lock ()
+  (skip-unless (treesit-ready-p 'lua))
+  (let ((treesit-font-lock-level 4))
+    (ert-font-lock-test-file (ert-resource-file "font-lock.lua") 
'lua-ts-mode)))
+
 (provide 'lua-ts-mode-tests)
 
 ;;; lua-ts-mode-tests.el ends here
diff --git a/test/lisp/progmodes/perl-mode-tests.el 
b/test/lisp/progmodes/perl-mode-tests.el
index a47a6722e20..e72bdf30711 100644
--- a/test/lisp/progmodes/perl-mode-tests.el
+++ b/test/lisp/progmodes/perl-mode-tests.el
@@ -45,7 +45,7 @@
     (skip-chars-forward " \t")
     (should (equal (current-column) perl-indent-level))))
 
-;;;; Re-use cperl-mode tests
+;;;; Reuse cperl-mode tests
 
 (defvar cperl-test-mode)
 (setq cperl-test-mode #'perl-mode)
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby.rb 
b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
index 81d0dfd75c9..a411b39a8fc 100644
--- a/test/lisp/progmodes/ruby-mode-resources/ruby.rb
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
@@ -34,11 +34,11 @@ x = # "tot %q/to"; =
 # Regexp after whitelisted method.
 "abc".sub /b/, 'd'
 
-# Don't mismatch "sub" at the end of words.
-a = asub / aslb + bsub / bslb;
+# Don't mistake division for regexp.
+a = sub / aslb + bsub / bslb;
 
 # Highlight the regexp after "if".
-x = toto / foo if /do bar/ =~ "dobar"
+x = toto / foo if / do bar/ =~ "dobar"
 
 # Regexp options are highlighted.
 
diff --git a/test/lisp/progmodes/ruby-mode-tests.el 
b/test/lisp/progmodes/ruby-mode-tests.el
index 117385ea3e8..fea5f58b92e 100644
--- a/test/lisp/progmodes/ruby-mode-tests.el
+++ b/test/lisp/progmodes/ruby-mode-tests.el
@@ -157,6 +157,18 @@ VALUES-PLIST is a list with alternating index and value 
elements."
 (ert-deftest ruby-regexp-is-not-mistaken-for-slash-symbol ()
   (ruby-assert-state "x = /foo:/" 3 nil))
 
+(ert-deftest ruby-slash-not-regexp-when-surrounded-by-spaces ()
+  (ruby-assert-state "x = index / 3" 3 nil))
+
+(ert-deftest ruby-slash-not-regexp-when-no-spaces ()
+  (ruby-assert-state "x = index/3" 3 nil))
+
+(ert-deftest ruby-regexp-not-division-when-only-space-before ()
+  (ruby-assert-state "x = foo_index /3" 3 ?/))
+
+(ert-deftest ruby-slash-not-regexp-when-only-space-after ()
+  (ruby-assert-state "x = index/ 3" 3 nil))
+
 (ert-deftest ruby-indent-simple ()
   (ruby-should-indent-buffer
    "if foo
diff --git a/test/lisp/thingatpt-tests.el b/test/lisp/thingatpt-tests.el
index 7cf41d2817b..98ebf771717 100644
--- a/test/lisp/thingatpt-tests.el
+++ b/test/lisp/thingatpt-tests.el
@@ -85,16 +85,16 @@
     ("<foo@example.com>" 5 email "<foo@example.com>")
     ("<foo@example.com>" 16 email "<foo@example.com>")
     ("<foo@example.com>" 17 email "<foo@example.com>")
-    ;; email adresses containing numbers
+    ;; email addresses containing numbers
     ("foo1@example.com" 1 email "foo1@example.com")
     ("1foo@example.com" 1 email "1foo@example.com")
     ("11@example.com" 1 email "11@example.com")
     ("1@example.com" 1 email "1@example.com")
-    ;; email adresses user portion containing dots
+    ;; email addresses user portion containing dots
     ("foo.bar@example.com" 1 email "foo.bar@example.com")
     (".foobar@example.com" 1 email nil)
     (".foobar@example.com" 2 email "foobar@example.com")
-    ;; email adresses domain portion containing dots and dashes
+    ;; email addresses domain portion containing dots and dashes
     ("foobar@.example.com" 1 email nil)
     ("foobar@-example.com" 1 email "foobar@-example.com")
     ;; These are illegal, but thingatpt doesn't yet handle them
diff --git a/test/src/comp-resources/comp-test-funcs.el 
b/test/src/comp-resources/comp-test-funcs.el
index 85282e4dc97..4b5f61d504f 100644
--- a/test/src/comp-resources/comp-test-funcs.el
+++ b/test/src/comp-resources/comp-test-funcs.el
@@ -543,6 +543,22 @@
    (if (comp-test-struct-p pkg) x)
    t))
 
+
+(cl-defstruct comp-test-time
+  unix)
+
+(defun comp-test-67239-00-f (a)
+  (cl-assert (stringp a)))
+
+(defsubst comp-test-67239-0-f (x _y)
+  (cl-etypecase x
+    (comp-test-time (error "foo"))
+    (string (comp-test-67239-00-f x))))
+
+(defun comp-test-67239-1-f ()
+  (let ((time (make-comp-test-time :unix (time-convert (current-time) 
'integer))))
+    (comp-test-67239-0-f "%F" time)))
+
 
 ;;;;;;;;;;;;;;;;;;;;
 ;; Tromey's tests ;;
diff --git a/test/src/comp-tests.el b/test/src/comp-tests.el
index c2f0af51570..92b66496c46 100644
--- a/test/src/comp-tests.el
+++ b/test/src/comp-tests.el
@@ -582,6 +582,10 @@ dedicated byte-op code."
       (advice-remove #'delete-region f)
       (should (equal comp-test-primitive-redefine-args '(1 2))))))
 
+(comp-deftest 67239-1 ()
+  "<https://lists.gnu.org/archive/html/bug-gnu-emacs/2023-11/msg00925.html>"
+  (should-not (comp-test-67239-1-f)))
+
 
 ;;;;;;;;;;;;;;;;;;;;;
 ;; Tromey's tests. ;;
diff --git a/test/src/regex-emacs-tests.el b/test/src/regex-emacs-tests.el
index 615d905e140..2912ce8a571 100644
--- a/test/src/regex-emacs-tests.el
+++ b/test/src/regex-emacs-tests.el
@@ -912,7 +912,7 @@ This evaluates the TESTS test cases from glibc."
     ))
 
 (ert-deftest regexp-tests-zero-width-assertion-repetition ()
-  ;; Check compatibility behaviour with repetition operators after
+  ;; Check compatibility behavior with repetition operators after
   ;; certain zero-width assertions (bug#64128).
 
   ;; This function is just to hide ugly regexps from relint so that it



reply via email to

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