emacs-diffs
[Top][All Lists]
Advanced

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

scratch/pkg 54ec3973e2: Merge remote-tracking branch 'origin/master' int


From: Gerd Moellmann
Subject: scratch/pkg 54ec3973e2: Merge remote-tracking branch 'origin/master' into scratch/pkg
Date: Mon, 19 Dec 2022 08:29:19 -0500 (EST)

branch: scratch/pkg
commit 54ec3973e298c3d2b3d81484f80053d881694f88
Merge: b182f18017 cb242bf151
Author: Gerd Möllmann <gerd@gnu.org>
Commit: Gerd Möllmann <gerd@gnu.org>

    Merge remote-tracking branch 'origin/master' into scratch/pkg
---
 .gitignore                                         |    4 +
 ChangeLog.2                                        |    2 +-
 ChangeLog.3                                        |   48 +-
 admin/check-man-pages                              |   56 +
 admin/cus-test.el                                  |   32 +-
 admin/git-bisect-start                             | 1627 ++++++++++++++-
 admin/make-tarball.txt                             |    6 +
 admin/merge-gnulib                                 |    5 +-
 admin/notes/git-workflow                           |    8 +-
 admin/notes/repo                                   |    8 +-
 admin/notes/tree-sitter/build-module/batch.sh      |    7 +
 admin/notes/tree-sitter/build-module/build.sh      |   73 +-
 admin/notes/tree-sitter/starter-guide              |    2 +-
 configure.ac                                       |   24 +-
 doc/emacs/macos.texi                               |    2 +-
 doc/emacs/misc.texi                                |   41 +-
 doc/emacs/programs.texi                            |   31 +-
 doc/lispref/ChangeLog.1                            |    2 +-
 doc/lispref/display.texi                           |  139 +-
 doc/lispref/files.texi                             |   17 +-
 doc/lispref/internals.texi                         |   16 +-
 doc/lispref/keymaps.texi                           |    2 +-
 doc/lispref/modes.texi                             |   28 +-
 doc/lispref/package.texi                           |    4 +-
 doc/lispref/parsing.texi                           |   24 +-
 doc/lispref/sequences.texi                         |    2 +-
 doc/lispref/variables.texi                         |   40 +-
 doc/man/etags.1                                    |   10 +-
 doc/misc/Makefile.in                               |   19 +-
 doc/misc/eglot.texi                                |    7 +
 doc/misc/erc.texi                                  |  344 ++--
 doc/misc/eshell.texi                               |  139 +-
 doc/misc/eww.texi                                  |   12 +-
 doc/misc/flymake.texi                              |    2 +-
 doc/misc/org.org                                   |   15 +-
 doc/misc/rcirc.texi                                |    8 +-
 doc/misc/use-package.texi                          | 2163 ++++++++++++++++++++
 etc/DEBUG                                          |   22 +
 etc/ERC-NEWS                                       |    4 +-
 etc/HELLO                                          |    2 +-
 etc/NEWS                                           |   51 +-
 etc/NEWS.29                                        |  292 ++-
 etc/PROBLEMS                                       |   24 +-
 lib-src/etags.c                                    |   78 +-
 lib-src/seccomp-filter.c                           |    2 +
 lib/explicit_bzero.c                               |   74 -
 lib/gnulib.mk.in                                   |   28 +-
 lib/memset_explicit.c                              |   55 +
 lib/string.in.h                                    |   17 +
 lib/verify.h                                       |    2 +-
 lisp/ChangeLog.15                                  |    2 +-
 lisp/ChangeLog.16                                  |    4 +-
 lisp/ChangeLog.17                                  |    2 +-
 lisp/ansi-osc.el                                   |    8 +-
 lisp/apropos.el                                    |    2 +-
 lisp/auth-source-pass.el                           |   12 +-
 lisp/bs.el                                         |  130 +-
 lisp/buff-menu.el                                  |   23 +-
 lisp/calc/calc-units.el                            |   42 +-
 lisp/cedet/semantic/complete.el                    |    2 +-
 lisp/comint.el                                     |   12 +-
 lisp/cus-edit.el                                   |    2 +-
 lisp/descr-text.el                                 |    2 +-
 lisp/dired-aux.el                                  |   53 +-
 lisp/emacs-lisp/byte-opt.el                        |   10 +-
 lisp/emacs-lisp/byte-run.el                        |    3 +-
 lisp/emacs-lisp/bytecomp.el                        |   77 +
 lisp/emacs-lisp/checkdoc.el                        |   25 +-
 lisp/emacs-lisp/cl-extra.el                        |    2 +-
 lisp/emacs-lisp/comp.el                            |    7 +-
 lisp/emacs-lisp/gv.el                              |    6 +-
 lisp/emacs-lisp/macroexp.el                        |    2 +-
 lisp/emacs-lisp/oclosure.el                        |    8 +-
 lisp/emacs-lisp/package-vc.el                      |   65 +-
 lisp/emacs-lisp/package.el                         |    7 +-
 lisp/emacs-lisp/rx.el                              |   14 +-
 lisp/emacs-lisp/shortdoc.el                        |  154 +-
 lisp/emacs-lisp/subr-x.el                          |    7 +-
 lisp/emacs-lisp/tabulated-list.el                  |    2 -
 lisp/emulation/viper-cmd.el                        |    6 +-
 lisp/epa-ks.el                                     |    2 +-
 lisp/erc/erc-common.el                             |   19 +-
 lisp/erc/erc-compat.el                             |   15 +-
 lisp/erc/erc-networks.el                           |   81 +-
 lisp/erc/erc-sasl.el                               |   27 +-
 lisp/erc/erc-services.el                           |    2 +-
 lisp/erc/erc.el                                    |   88 +-
 lisp/eshell/em-alias.el                            |    4 +-
 lisp/eshell/em-cmpl.el                             |   26 +-
 lisp/eshell/em-unix.el                             |   12 +-
 lisp/eshell/esh-arg.el                             |  132 +-
 lisp/eshell/esh-cmd.el                             |   15 +-
 lisp/eshell/esh-opt.el                             |    4 +-
 lisp/eshell/esh-util.el                            |    6 +-
 lisp/eshell/esh-var.el                             |   35 +-
 lisp/external-completion.el                        |  176 ++
 lisp/files.el                                      |   88 +-
 lisp/gnus/ChangeLog.2                              |    2 +-
 lisp/gnus/ChangeLog.3                              |    2 +-
 lisp/gnus/gnus-icalendar.el                        |    2 +-
 lisp/gnus/nnmaildir.el                             |    2 +-
 lisp/icomplete.el                                  |    1 -
 lisp/ido.el                                        |    2 +-
 lisp/international/ogonek.el                       |    4 +-
 lisp/isearch.el                                    |    2 +-
 lisp/jsonrpc.el                                    |   19 +-
 lisp/keymap.el                                     |    2 +-
 lisp/language/european.el                          |    2 +-
 lisp/language/indian.el                            |   42 +-
 lisp/ldefs-boot.el                                 |  354 +++-
 lisp/leim/quail/cyrillic.el                        |  132 ++
 lisp/mail/rmailsum.el                              |   62 +-
 lisp/mh-e/mh-identity.el                           |    2 +-
 lisp/minibuffer.el                                 |    4 +-
 lisp/mouse-drag.el                                 |   19 +-
 lisp/mouse.el                                      |   20 +-
 lisp/net/ange-ftp.el                               |   19 +
 lisp/net/rcirc.el                                  |   21 +-
 lisp/net/tramp-archive.el                          |    9 +-
 lisp/net/tramp-crypt.el                            |    2 +-
 lisp/net/tramp-gvfs.el                             |    2 +-
 lisp/net/tramp-sh.el                               |    1 +
 lisp/net/tramp-smb.el                              |   13 +-
 lisp/net/tramp.el                                  |    6 +-
 lisp/org/ChangeLog.1                               |    2 +-
 lisp/org/ob-R.el                                   |    4 +-
 lisp/org/ob-clojure.el                             |    4 +-
 lisp/org/ob-comint.el                              |    8 +
 lisp/org/ob-core.el                                |    4 +-
 lisp/org/ob-octave.el                              |    2 +-
 lisp/org/oc-bibtex.el                              |    6 +-
 lisp/org/ol.el                                     |    6 +-
 lisp/org/org-clock.el                              |   95 +-
 lisp/org/org-element.el                            |    7 +-
 lisp/org/org-fold-core.el                          |    9 +-
 lisp/org/org-footnote.el                           |    9 +-
 lisp/org/org-persist.el                            |  249 +--
 lisp/org/org-table.el                              |   59 +-
 lisp/org/org-version.el                            |    2 +-
 lisp/org/org.el                                    |   18 +-
 lisp/org/ox-md.el                                  |    3 +-
 lisp/org/ox.el                                     |   38 +-
 lisp/outline.el                                    |    2 +-
 lisp/pcomplete.el                                  |    2 +-
 lisp/proced.el                                     |   52 +-
 lisp/progmodes/bat-mode.el                         |    2 +-
 lisp/progmodes/c-ts-mode.el                        |  112 +-
 lisp/progmodes/cc-defs.el                          |    2 +-
 lisp/progmodes/cmake-ts-mode.el                    |  234 +++
 lisp/progmodes/compile.el                          |    1 +
 lisp/progmodes/csharp-mode.el                      |   43 +-
 lisp/progmodes/dockerfile-ts-mode.el               |  177 ++
 lisp/progmodes/eglot.el                            |  207 +-
 lisp/progmodes/flymake.el                          |    7 +-
 lisp/progmodes/gdb-mi.el                           |   69 +-
 lisp/progmodes/go-ts-mode.el                       |  354 ++++
 lisp/progmodes/grep.el                             |    4 +
 lisp/progmodes/idlwave.el                          |    2 +-
 lisp/progmodes/java-ts-mode.el                     |   45 +-
 lisp/progmodes/js.el                               |   52 +-
 lisp/progmodes/json-ts-mode.el                     |   27 +-
 lisp/progmodes/prog-mode.el                        |   37 +-
 lisp/progmodes/project.el                          |   86 +-
 lisp/progmodes/python.el                           |   46 +-
 lisp/progmodes/ruby-mode.el                        |   74 +-
 lisp/progmodes/rust-ts-mode.el                     |  371 ++++
 lisp/progmodes/sh-script.el                        |    7 +
 lisp/progmodes/sql.el                              |    3 +-
 lisp/progmodes/typescript-ts-mode.el               |   82 +-
 lisp/progmodes/verilog-mode.el                     | 1588 +++++++++-----
 lisp/progmodes/which-func.el                       |   17 +-
 lisp/progmodes/xref.el                             |    2 +-
 lisp/replace.el                                    |   10 +-
 lisp/server.el                                     |  143 +-
 lisp/shell.el                                      |    1 +
 lisp/simple.el                                     |   95 +-
 lisp/so-long.el                                    |    2 +-
 lisp/subr.el                                       |    2 +-
 lisp/tab-bar.el                                    |  199 +-
 lisp/term/xterm.el                                 |    2 +
 lisp/textmodes/css-mode.el                         |    6 +-
 lisp/textmodes/emacs-news-mode.el                  |    2 +-
 lisp/textmodes/reftex.el                           |   11 +-
 lisp/textmodes/texinfo.el                          |    2 +
 lisp/textmodes/toml-ts-mode.el                     |  187 ++
 lisp/textmodes/yaml-ts-mode.el                     |  151 ++
 lisp/transient.el                                  |    4 +-
 lisp/treesit.el                                    |  427 +++-
 lisp/use-package/bind-key.el                       |  569 +++++
 lisp/use-package/use-package-bind-key.el           |  176 ++
 lisp/use-package/use-package-core.el               | 1691 +++++++++++++++
 lisp/use-package/use-package-delight.el            |   88 +
 lisp/use-package/use-package-diminish.el           |   77 +
 .../use-package-ensure-system-package.el           |  106 +
 lisp/use-package/use-package-ensure.el             |  212 ++
 lisp/use-package/use-package-jump.el               |   74 +
 lisp/use-package/use-package-lint.el               |   80 +
 lisp/use-package/use-package.el                    |   53 +
 lisp/vc/vc-git.el                                  |   11 +-
 lisp/vc/vc.el                                      |    2 +-
 lisp/windmove.el                                   |    3 +-
 lisp/window.el                                     |   17 +-
 m4/explicit_bzero.m4                               |   23 -
 m4/gnulib-comp.m4                                  |   18 +-
 m4/memset_explicit.m4                              |   20 +
 m4/string_h.m4                                     |    7 +-
 oldXMenu/ChangeLog.1                               |    2 +-
 src/ChangeLog.12                                   |    2 +-
 src/ChangeLog.13                                   |    2 +-
 src/alloc.c                                        |  274 ++-
 src/buffer.c                                       |   32 +-
 src/buffer.h                                       |   11 -
 src/editfns.c                                      |   24 +-
 src/emacs.c                                        |    6 +
 src/fileio.c                                       |   42 +-
 src/fns.c                                          |   11 +-
 src/frame.h                                        |    1 -
 src/gnutls.c                                       |    2 +-
 src/gtkutil.c                                      |    6 +-
 src/image.c                                        |    9 +
 src/itree.c                                        |    4 +-
 src/itree.h                                        |    2 +-
 src/lisp.h                                         |   20 +
 src/lread.c                                        |   27 +-
 src/pdumper.c                                      |    1 -
 src/sysdep.c                                       |    7 +-
 src/timefns.c                                      |    4 +
 src/treesit.c                                      |  534 +++--
 src/window.c                                       |   10 +-
 src/xdisp.c                                        |   21 +-
 src/xfaces.c                                       |   90 +-
 src/xfns.c                                         |   39 +-
 src/xselect.c                                      |  122 +-
 src/xterm.c                                        |  439 ++--
 src/xterm.h                                        |   11 +-
 test/README                                        |    2 +-
 test/infra/gitlab-ci.yml                           |   28 +-
 test/infra/test-jobs.yml                           |   17 +
 test/lisp/auth-source-pass-tests.el                |   31 +-
 test/lisp/calendar/icalendar-tests.el              |    3 +-
 test/lisp/comint-tests.el                          |   16 +-
 test/lisp/delim-col-tests.el                       |    2 +-
 test/lisp/emacs-lisp/bytecomp-tests.el             |   64 +-
 test/lisp/emacs-lisp/cconv-tests.el                |    4 +-
 test/lisp/emacs-lisp/checkdoc-tests.el             |   12 +-
 test/lisp/emacs-lisp/cl-lib-tests.el               |    5 +-
 test/lisp/emacs-lisp/find-func-tests.el            |    2 +-
 test/lisp/emacs-lisp/lisp-mnt-tests.el             |   12 +-
 test/lisp/emacs-lisp/rx-tests.el                   |    6 +
 test/lisp/emacs-lisp/subr-x-tests.el               |   11 +-
 test/lisp/erc/erc-networks-tests.el                |   37 +-
 test/lisp/erc/erc-scenarios-auth-source.el         |   31 +-
 .../erc/erc-scenarios-base-association-nick.el     |   29 +-
 .../erc/erc-scenarios-base-association-query.el    |  107 +
 .../erc/erc-scenarios-base-association-samenet.el  |   29 +-
 test/lisp/erc/erc-scenarios-base-association.el    |   29 +-
 .../erc-scenarios-base-compat-rename-bouncer.el    |   29 +-
 test/lisp/erc/erc-scenarios-base-local-modules.el  |   31 +-
 .../erc/erc-scenarios-base-misc-regressions.el     |   29 +-
 .../erc/erc-scenarios-base-netid-bouncer-id.el     |   29 +-
 .../erc-scenarios-base-netid-bouncer-recon-base.el |   29 +-
 .../erc-scenarios-base-netid-bouncer-recon-id.el   |   29 +-
 test/lisp/erc/erc-scenarios-base-netid-bouncer.el  |   29 +-
 test/lisp/erc/erc-scenarios-base-netid-samenet.el  |   32 +-
 test/lisp/erc/erc-scenarios-base-reconnect.el      |   29 +-
 test/lisp/erc/erc-scenarios-base-renick.el         |   29 +-
 test/lisp/erc/erc-scenarios-base-reuse-buffers.el  |   29 +-
 test/lisp/erc/erc-scenarios-base-unstable.el       |   29 +-
 .../erc/erc-scenarios-base-upstream-recon-soju.el  |   31 +-
 .../erc/erc-scenarios-base-upstream-recon-znc.el   |   31 +-
 test/lisp/erc/erc-scenarios-internal.el            |   29 +-
 test/lisp/erc/erc-scenarios-join-auth-source.el    |   29 +-
 .../lisp/erc/erc-scenarios-join-netid-newcmd-id.el |   29 +-
 test/lisp/erc/erc-scenarios-join-netid-newcmd.el   |   29 +-
 test/lisp/erc/erc-scenarios-join-netid-recon-id.el |   29 +-
 test/lisp/erc/erc-scenarios-join-netid-recon.el    |   29 +-
 test/lisp/erc/erc-scenarios-misc.el                |   34 +-
 test/lisp/erc/erc-scenarios-sasl.el                |   27 +-
 test/lisp/erc/erc-scenarios-services-misc.el       |   88 +-
 test/lisp/erc/erc-tests.el                         |    7 +-
 .../erc/resources/base/assoc/queries/netnick.eld   |   42 +
 .../erc/resources/base/assoc/queries/non-erc.eld   |   33 +
 .../erc/resources/base/local-modules/fourth.eld    |    2 +-
 test/lisp/erc/resources/erc-d/erc-d-i.el           |   27 +-
 test/lisp/erc/resources/erc-d/erc-d-t.el           |   30 +-
 test/lisp/erc/resources/erc-d/erc-d-tests.el       |   30 +-
 test/lisp/erc/resources/erc-d/erc-d-u.el           |   27 +-
 test/lisp/erc/resources/erc-d/erc-d.el             |   27 +-
 .../resources/erc-d/resources/proxy-subprocess.el  |   28 +-
 test/lisp/erc/resources/erc-scenarios-common.el    |   29 +-
 .../networks/announced-missing/foonet.eld          |    3 -
 .../erc/resources/services/auth-source/recon.eld   |   48 +
 test/lisp/eshell/em-alias-tests.el                 |    9 +
 test/lisp/eshell/esh-arg-tests.el                  |  105 +
 test/lisp/eshell/esh-var-tests.el                  |   74 +
 test/lisp/eshell/eshell-tests.el                   |   31 -
 test/lisp/files-tests.el                           |   26 +-
 test/lisp/gnus/mml-sec-tests.el                    |    2 +-
 test/lisp/international/ucs-normalize-tests.el     |    3 +-
 test/lisp/loadhist-resources/loadhist--bar.el      |    8 +-
 test/lisp/loadhist-resources/loadhist--foo.el      |    8 +-
 test/lisp/proced-tests.el                          |  105 +
 test/lisp/progmodes/eglot-tests.el                 | 1320 ++++++++++++
 .../progmodes/project-resources/.dir-locals.el     |    1 +
 test/lisp/progmodes/project-resources/etc          |    1 +
 test/lisp/progmodes/project-resources/foo          |    1 +
 test/lisp/progmodes/project-tests.el               |   15 +-
 test/lisp/progmodes/ruby-mode-resources/ruby.rb    |   38 +
 test/lisp/progmodes/ruby-mode-tests.el             |   39 +
 test/lisp/server-tests.el                          |    6 +-
 test/lisp/use-package/use-package-tests.el         | 1959 ++++++++++++++++++
 test/manual/noverlay/itree-tests.c                 |  182 +-
 test/src/sqlite-tests.el                           |    1 +
 test/src/treesit-tests.el                          |  472 +++++
 314 files changed, 20466 insertions(+), 3737 deletions(-)

diff --git a/.gitignore b/.gitignore
index f4d2c15f51..af0ba0eb41 100644
--- a/.gitignore
+++ b/.gitignore
@@ -334,3 +334,7 @@ lib-src/seccomp-filter-exec.pfc
 # Ignore a directory used by dap-mode.
 .vscode
 /test/gmp.h
+
+# GDB history
+.gdb_history
+_gdb_history
diff --git a/ChangeLog.2 b/ChangeLog.2
index 143be59c9e..5d4c1afc36 100644
--- a/ChangeLog.2
+++ b/ChangeLog.2
@@ -28676,7 +28676,7 @@
        * lisp/faces.el (set-face-attribute): Don't be fooled too easily
        by a hyphen in a font's name.
 
-       Fix value of posn-at-pont in R2L lines
+       Fix value of posn-at-point in R2L lines
        * src/keyboard.c (Fposn_at_x_y, Fposn_at_point): Allow X pixel
        coordinate of -1, for a newline in a right-to-left line that
        overflowed into the left fringe.
diff --git a/ChangeLog.3 b/ChangeLog.3
index 136a276b63..4b3507bae3 100644
--- a/ChangeLog.3
+++ b/ChangeLog.3
@@ -1654,7 +1654,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  Eli Zaretskii  <eliz@gnu.org>
 
@@ -14724,7 +14724,7 @@
 
        * lisp/icomplete.el (icomplete-vertical-mode):
        (fido-vertical-mode): Tweak docstring.  Turn on
-       icomplete-mode. and fido-mdoe
+       icomplete-mode. and fido-mode
 
 2021-08-16  Glenn Morris  <rgm@gnu.org>
 
@@ -20654,7 +20654,7 @@
        * lisp/progmodes/cc-engine.el (c-clear-<-pair-props, 
c-clear->-pair-props)
        (c-clear-<-pair-props-if-match-after, 
c-clear->-pair-props-if-match-before)
        (c-forward-<>-arglist-recur):
-       Invalidate caches with c-trunctate-lit-pos-cache.
+       Invalidate caches with c-truncate-lit-pos-cache.
        (c-forward-<>-arglist-recur): If in a matching <...> expression, the < 
has a
        syntax-table property, but the > not, remove that property.
 
@@ -28297,7 +28297,7 @@
 
 2021-04-17  Eli Zaretskii  <eliz@gnu.org>
 
-       * src/emacs.c (load_pdump): Fix compilation on picky-complier platforms.
+       * src/emacs.c (load_pdump): Fix compilation on picky-compiler platforms.
 
 2021-04-17  Daniel Martín  <mardani29@yahoo.es>
 
@@ -29362,7 +29362,7 @@
        Make the function correctly recognize a brace block preceded by an
        introductory line without a parameter list.
 
-       * lisp/progmodes/cc-cmds.el (c-where-wrt-brace-contruct): Reintroduce 
the use
+       * lisp/progmodes/cc-cmds.el (c-where-wrt-brace-construct): Reintroduce 
the use
        of c-beginning-of-decl-1, which was removed some weeks ago, in place of 
a
        c-syntactic-skip-backward.  Reformulate the code generally.
 
@@ -31051,7 +31051,7 @@
 
 2021-03-28  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Clarify the doc string of plist-memeber and plist-put
+       Clarify the doc string of plist-member and plist-put
 
        * src/fns.c (Fplist_member):
        (Fplist_put): Clarify what comparison function is used for PROP
@@ -35236,7 +35236,7 @@
 
 2021-03-04  Andrea Corallo  <akrl@sdf.org>
 
-       * src/comp.c (hash_native_abi): Account for 
`system-configuraton-options'.
+       * src/comp.c (hash_native_abi): Account for 
`system-configuration-options'.
 
 2021-03-04  Glenn Morris  <rgm@gnu.org>
 
@@ -46491,7 +46491,7 @@
 
        Fix Quit button in dictionary buffer
 
-       * lisp/net/dictionary.el (dictionay-close): Changing the arity of the
+       * lisp/net/dictionary.el (dictionary-close): Changing the arity of the
        function in cc5f2803785c5dc785f09a292313cf799e8d29bb was a mistake.
        Restore it, but mark the argument as unused to avoid a
        wrong-number-of-arguments error when using the Quit button.
@@ -80628,7 +80628,7 @@
 
 2020-05-17  Andrea Corallo  <akrl@sdf.org>
 
-       Fix Garbage Collector for missing calle-saved regs content (Bug#41357)
+       Fix Garbage Collector for missing callee-saved regs content (Bug#41357)
 
        * src/alloc.c (SET_STACK_TOP_ADDRESS): Do not call
        __builtin_unwind_init.
@@ -88998,7 +88998,7 @@
 
 2020-01-19  Stefan Kangas  <stefankangas@gmail.com>
 
-       Make arguments to dired-chage-marks non-optional
+       Make arguments to dired-change-marks non-optional
 
        * lisp/dired.el (dired-change-marks): Make arguments
        non-optional.  (Bug#29842)
@@ -103735,7 +103735,7 @@
 
        Fixes bug#38131.
 
-       This is not the best way to have fido-mdoe emulate that particular bit
+       This is not the best way to have fido-mode emulate that particular bit
        of ido-mode.
 
        This reverts commit 5761a1a3939e23d8e8c725241dd9398a12f191b0.
@@ -113661,7 +113661,7 @@
 
 2019-09-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
-       Make the NSM not pop up an X dialogue on non-mouse actions
+       Make the NSM not pop up an X dialog on non-mouse actions
 
        * lisp/emacs-lisp/rmc.el (read-multiple-choice): Don't pop up X
        dialogs on (url-retrieve "https://expired.badssl.com/"; #'ignore)
@@ -118445,7 +118445,7 @@
        internal variable...
        (browse-url-browser-function, browse-url-external-browser): Used
        by these two; the latter of which is a new variable.
-       (browse-url-botton-regexp): New variable.
+       (browse-url-button-regexp): New variable.
        (browse-url-button-map): New keymap.
        (browse-url-button): New face.
        (browse-url-add-buttons): New function to add clickable browse-url
@@ -124088,7 +124088,7 @@
        This is fine when the GPG key is cached and each entry can be
        decrypted without user interaction.  However, for security some people
        have their GPG on a hardware token like a Yubikey setup so that they
-       have to touch a sensor on the toke for every cryptographic operation,
+       have to touch a sensor on the token for every cryptographic operation,
        in which case it becomes inconvenient as each attempt to find an entry
        requires a variable number of touches of the hardware token.
 
@@ -139023,7 +139023,7 @@
        Add 'breakpoint' to builtins for Python
 
        * lisp/progmodes/python.el (python-font-lock-keywords-level-2)
-       (python-font-lock-keywords-maxiumum-decoration): Add 'breakpoint'
+       (python-font-lock-keywords-maximum-decoration): Add 'breakpoint'
        to the list of builtins, it's new as of Python 3.7.
 
 2019-03-01  Eli Zaretskii  <eliz@gnu.org>
@@ -143055,7 +143055,7 @@
 
 2019-01-05  João Távora  <joaotavora@gmail.com>
 
-       New flymake-supress-zero-counters defcustom
+       New flymake-suppress-zero-counters defcustom
 
        A feature suggested by Yuri Khan <yurivkhan@gmail.com>.
 
@@ -185861,7 +185861,7 @@
        (flymake-start-syntax-check-on-find-file): Obsolete alias for
        flymake-start-on-flymake-mode.
        (flymake-start): Redesign.  Affect the global post-command-hook
-       and local window-configuraiton-change-hook.
+       and local window-configuration-change-hook.
        (flymake--schedule-timer-maybe)
        (flymake-after-change-function, flymake-after-save-hook): Pass
        t to flymake-start.
@@ -190903,7 +190903,7 @@
        (initFrameFromEmacs) [NS_IMPL_COCOA]: Handle ns-appearance and
        ns-transparent-titlebar frame parameters.
        * doc/lispref/frames.texi (Window Management Parameters): Document
-       ns-apperance and ns-transparent-titlebar.
+       ns-appearance and ns-transparent-titlebar.
 
 2017-08-22  Alan Mackenzie  <acm@muc.de>
 
@@ -202762,7 +202762,7 @@
        (w32_frame_parm_handlers): Add entries for new frame
        parameters.
        * src/w32font.c (Fx_select_font): Handle `z-group-above'
-       frames during font selection dialogue.
+       frames during font selection dialog.
        * src/w32term.c (construct_mouse_wheel): Construct mouse wheel
        event from F's w32 window.
        (w32_mouse_position): Handle child frames.
@@ -204016,7 +204016,7 @@
 
 2017-04-02  Michael Albinus  <michael.albinus@gmx.de>
 
-       Apply connecion-local variables for shells
+       Apply connection-local variables for shells
 
        * doc/misc/tramp.texi (Remote processes): Show use of connection-local
        variables.  Don't mention Emacs 23 anymore.
@@ -204027,7 +204027,7 @@
        (connection-local-set-profiles, with-connection-local-profiles):
        Adapt docstring.
 
-       * lisp/shell.el (shell): Apply connecion-local variables.
+       * lisp/shell.el (shell): Apply connection-local variables.
 
 2017-04-01  Evgeni Kolev  <evgenysw@gmail.com>  (tiny change)
 
@@ -206673,7 +206673,7 @@
        * lisp/emacs-lisp/package.el (package-initialize): Check
        `after-init-time' rather than `load-file-name' to decide if
        `package--ensure-init-file' should be called.  Depending on
-       `load-file-name' will fail if the user calls `pacakge-initialize' in
+       `load-file-name' will fail if the user calls `package-initialize' in
        file which is loaded from the init file (Bug#24643, Bug#25819).
 
 2017-02-26  Eli Zaretskii  <eliz@gnu.org>
@@ -229958,7 +229958,7 @@
        Use #' read syntax for functions.
        (file-notify-test05-dir-validity)
        (file-notify-test06-many-events): Simplify directory creation.
-       (file-notify-test09-sufficient-ressources): New test.
+       (file-notify-test09-sufficient-resources): New test.
 
 2016-03-04  Lars Ingebrigtsen  <larsi@gnus.org>
 
@@ -231088,7 +231088,7 @@
        * lisp/gnus/gnus-rfc1843.el: New file for Gnus/rfc1843
        interface functions.
 
-       * lisp/gnus/gnus-rfc1843.el: Move all Gnus-specifig functions to
+       * lisp/gnus/gnus-rfc1843.el: Move all Gnus-specific functions to
        gnus-rfc1843.
 
 2016-02-22  Lars Ingebrigtsen  <larsi@gnus.org>
diff --git a/admin/check-man-pages b/admin/check-man-pages
new file mode 100755
index 0000000000..c7d781ba3d
--- /dev/null
+++ b/admin/check-man-pages
@@ -0,0 +1,56 @@
+#!/bin/bash
+### check-man-pages - check man pages for errors
+
+## Copyright (C) 2022 Free Software Foundation, Inc.
+
+## Author: Stefan Kangas <stefankangas@gmail.com>
+
+## 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:
+
+## Check Emacs man pages for errors using `man'.
+
+### Code:
+
+source "${0%/*}/emacs-shell-lib"
+
+exit_status=0
+
+cd "$PD"/../doc/man
+for page in *.1; do
+    # ctags.1 just includes the man page etags.1, which AFAICT will
+    # default to the one installed on the system (!), instead of the
+    # one in the repository.  So checking it is pointless, and we will
+    # in any case already check etags.1 separately.
+    if [ "$page" == "ctags.1" ]; then
+        continue
+    fi
+    log=$(emacs_mktemp)
+    LC_ALL=C.UTF-8 MANROFFSEQ='' MANWIDTH=80 \
+        man --warnings=all,mac -E UTF-8 -l -Tutf8 -Z "$page" >/dev/null 2> 
"$log"
+    log_size=$(stat --format=%s "$log")
+    if [ "$log_size" -ne 0 ]; then
+        echo "doc/man/$page:"
+        # Point to the correct file for *compilation* buffers.
+        cat "$log" \
+            | sed 's/troff: man1\/\([^ ]\+\)\.1/troff: doc\/man\/\1.1/' \
+            | sed "s/<standard input>/doc\/man\/$page/"
+        exit_status=1
+    fi
+done
+
+exit $exit_status
diff --git a/admin/cus-test.el b/admin/cus-test.el
index 7e73f2e44a..44897cd106 100644
--- a/admin/cus-test.el
+++ b/admin/cus-test.el
@@ -145,7 +145,8 @@ Names should be as they appear in loaddefs.el.")
 (require 'cus-load)
 
 (defvar cus-test-errors nil
-  "List of problematic variables found by `cus-test-apropos'.")
+  "List of problematic variables found by `cus-test-apropos'.
+Each element is (VARIABLE . PROBLEM); see `cus-test--format-problem'.")
 
 (defvar cus-test-tested-variables nil
   "List of options tested by last call of `cus-test-apropos'.")
@@ -181,6 +182,15 @@ Set by `cus-test-noloads'.")
 ;; (defvar cus-test-vars-cus-loaded nil
 ;;   "A list of options loaded by `custom-load-symbol'.")
 
+(defun cus-test--format-error (err)
+  "Format an element of `cus-test-errors'."
+  (pcase err
+    (`(,var :type-error ,value ,type)
+     (format "variable: %s\n   value: %S\n    type: %S" var value type))
+    (`(,var :other-error ,e)
+     (format "variable: %s\n   error: %S" var e))
+    (_ (format "%S" err))))
+
 (defun cus-test-apropos (regexp)
   "Check the options matching REGEXP.
 The detected problematic options are stored in `cus-test-errors'."
@@ -200,8 +210,7 @@ The detected problematic options are stored in 
`cus-test-errors'."
         (let* ((type (custom-variable-type symbol))
                (conv (widget-convert type))
                (get (or (get symbol 'custom-get) 'default-value))
-               values
-               mismatch)
+               values)
           (when (default-boundp symbol)
             (push (funcall get symbol) values)
             (push (eval (car (get symbol 'standard-value)) t) values))
@@ -215,7 +224,9 @@ The detected problematic options are stored in 
`cus-test-errors'."
                   ;; TODO for booleans, check for values that can be
                   ;; evaluated and are not t or nil.  Usually a bug.
                   (unless (widget-apply conv :match value)
-                    (setq mismatch 'mismatch)))
+                     (let ((err (list symbol :type-error value type)))
+                       (unless (member err cus-test-errors)
+                         (push err cus-test-errors)))))
                 values)
 
           ;; Store symbols with a custom-get property.
@@ -231,13 +242,12 @@ The detected problematic options are stored in 
`cus-test-errors'."
             (and (consp c-value)
                  (boundp symbol)
                  (not (equal (eval (car c-value) t) (symbol-value symbol)))
-                 (add-to-list 'cus-test-vars-with-changed-state symbol)))
-
-          (if mismatch
-              (push symbol cus-test-errors)))
+                 (add-to-list 'cus-test-vars-with-changed-state symbol))))
 
        (error
-       (push symbol cus-test-errors)
+        (let ((err (list symbol :other-error alpha)))
+          (unless (member err cus-test-errors)
+           (push err cus-test-errors)))
        (message "Error for %s: %s" symbol alpha))))
    (cus-test-get-options regexp))
   (message "%s options tested"
@@ -292,7 +302,7 @@ currently defined groups."
        (insert "No errors found by cus-test.")
       (insert "The following variables seem to have problems:\n\n")
       (dolist (e cus-test-errors)
-       (insert (symbol-name e) "\n")))))
+       (insert (cus-test--format-error e) "\n")))))
 
 (defun cus-test-load-custom-loads ()
   "Call `custom-load-symbol' on all atoms."
@@ -399,7 +409,7 @@ Returns a list of variables with suspicious types."
         (message "No problems found")
         nil)
     (message "The following options might have problems:")
-    (cus-test-message cus-test-errors)
+    (cus-test-message (mapcar #'cus-test--format-error cus-test-errors))
     cus-test-errors))
 
 (defun cus-test-deps ()
diff --git a/admin/git-bisect-start b/admin/git-bisect-start
index cf0c8cde41..945d4901c1 100755
--- a/admin/git-bisect-start
+++ b/admin/git-bisect-start
@@ -1,7 +1,8 @@
 #!/bin/bash
 
-### Start a git bisection, and prune the branches that are the result of
-### merging external trees into the Emacs repository.
+### Start a git bisection, ensuring that commits in branches that are
+### the result of merging external trees into the Emacs repository, as
+### well as certain commits on which Emacs fails to build, are skipped.
 
 ## Copyright (C) 2022 Free Software Foundation, Inc.
 
@@ -22,19 +23,1617 @@
 
 ### Commentary:
 
-## Marking the last commits of external tree merges as "good" ensures
-## that all the commits between the external tree root and the merge
-## (excluding the merge-commit itself) are regarded as "good", so "git
-## bisect" will never descend into these branches, which only have the
-## files of the external tree, and in which Emacs can therefore not be
-## built.  The last commit is the parent of the merge commit in the
-## external tree, that is, the parent of the merge commit that is not
-## on master.
+## This script can be executed directly, at the root of the Emacs
+## repository, with:
+##
+## ./admin/git-bisect-start
+##
+## The arguments to that script, if any, are passed to 'git bisect
+## start' (see 'git help bisect' for a description of the arguments
+## that can be used with 'git bisect start').
+##
+## It can also be executed automatically, when 'git bisect start' is
+## called, with the help of the following wrapper script, that should
+## be named 'git' and should be placed before the actual git binary in
+## PATH.  This is useful in particular when git is used through an
+## interface such as Magit.
+##
+## #!/bin/bash
+## REAL_GIT=$(which -a git | sed -n 2p)
+## [ -z $REAL_GIT ] && { echo "fatal: 'git' not found"; exit 128; }
+## if [[ "$($REAL_GIT rev-parse --show-toplevel 2> /dev/null)" == "$(pwd)" ]] 
&&
+##    [ -x ./admin/git-bisect-start ] &&
+##    [[ "$1" == "bisect" && "$2" == "start" ]]
+## then
+##   shift 2
+##   exec env REAL_GIT=$REAL_GIT ./admin/git-bisect-start "$@"
+## else
+##   exec $REAL_GIT "$@"
+## fi
 
 ### Code:
 
-git bisect start
+[ -z $REAL_GIT ] && REAL_GIT=git
+
+$REAL_GIT bisect start "$@"
+
+## After the merge of an external tree, the last commit in the
+## external tree and all its parents should be skipped, because Emacs
+## cannot be built on these commits, as they only contain the files of
+## the external tree.  That last commit that should be placed after a
+## '# SKIP-BRANCH ' below is the parent of the merge commit in the
+## external tree, that is, the parent of the merge commit that is not
+## already on master.  In other words, it is the parent of the merge
+## commit for which 'git rev-list --max-parents=0 <commit>' does not
+## include ce5584125c44a1a2fbb46e810459c50b227a95e2 (which is the root
+## commit of the Emacs respository).
+
+for C in $(cat $0 | grep '^# SKIP-BRANCH ' | sed 's/^# SKIP-BRANCH //')
+do
+  $REAL_GIT bisect skip $($REAL_GIT rev-list $C)
+done
+
+# Prune commits 1e5b753bf4..806734c1b1 introduced by 0186faf2a1
+# (Eglot merge on Oct 20 2022)
+# SKIP-BRANCH 806734c1b1f433de43d59d9a5e3a1e89d64315f6
+
+# Prune commits 31ea42e15e..58cc931e92 introduced by 4a1e9d61b5
+# (use-package merge on Nov 30 2022)
+# SKIP-BRANCH 58cc931e92ece70c3e64131ee12a799d65409100
+
+## The list below is the exhaustive list of all commits between Dec 1
+## 2016 and Nov 30 2022 on which building Emacs with the default
+## options, on a GNU/Linux computer and with GCC, fails.  It is
+## possible (though unlikely) that building Emacs with non-default
+## options, with other compilers, or on other platforms, would succeed
+## on some of these commits.  It is of course also possible (and
+## likely) that building Emacs on some commits not present in that
+## list will fail with non-default options, with other compilers, or
+## on other platforms.
+
+$REAL_GIT bisect skip $(cat $0 | grep '^# SKIP-SINGLE ' | sed 's/^# 
SKIP-SINGLE //')
 
-# Prune commits 1e5b753bf4..806734c1b1 introduced by 0186faf2a1 (Eglot
-# merge on Oct 20 2022)
-git bisect good 806734c1b1f433de43d59d9a5e3a1e89d64315f6
+# SKIP-SINGLE f37f93f364aed34275f515a8c933f48a0e2735b9
+# SKIP-SINGLE ba8e883fa30f1267c27751c1ee9df25a5dde4c0c
+# SKIP-SINGLE 3ef50c1ff691b0a6c2f56da76f7c1c9b572d8be8
+# SKIP-SINGLE 54f52a1390c394f42203f39d0b4d73318203e092
+# SKIP-SINGLE 128cacda1c79983f0b64773afc029bc757cfb7b8
+# SKIP-SINGLE fa7d1f075fb862ae4ca28390abf33d625dbd2813
+# SKIP-SINGLE 16ac7c0fc91b5eb09f2a129fc2c01281369f897a
+# SKIP-SINGLE 8ad92413b9349613f9815bd0aaf523896a84b479
+# SKIP-SINGLE 137898d89359c63ec05d7bb5eedc2d2f59102a11
+# SKIP-SINGLE 66a5abb102ec1d6e4c327632ef235d1eb6433291
+# SKIP-SINGLE e4deba098e0281538a0e7b04d849989f17e5bcc7
+# SKIP-SINGLE de4624c99ea5bbe38ad5aff7b6461cc5c740d0be
+# SKIP-SINGLE bfa88520136dd6b187ba101e6db5a5f8f0d5e874
+# SKIP-SINGLE f441451658ecb8d0d8ba386d9fd3eebf3b17d549
+# SKIP-SINGLE bf7f7c0d82a56ed1b76358657e74ca2833b19fe2
+# SKIP-SINGLE a1cb68be6c94513c436fd52e4453cb7afe28f2ba
+# SKIP-SINGLE 25d38a06eceb0853190a2d9acf53d85686f524bd
+# SKIP-SINGLE a7e4870f165e9fd36d5cfcabb19b215b94373602
+# SKIP-SINGLE 6a82d19db18f8480342cc4c1a0ad76c75df41941
+# SKIP-SINGLE cd0e63652445c90af7167b48d83e410af1e6e590
+# SKIP-SINGLE 097b1686b6ac518ba8c2ae225eb62560c2010431
+# SKIP-SINGLE 27accec97022a49b362feeb36293fdce2947eb43
+# SKIP-SINGLE e0e95199b93a232e5d4da67823364676ca9cb67c
+# SKIP-SINGLE 36cbe217c818000d90fea132f0c8041f06748502
+# SKIP-SINGLE 6b4195f2ace1f6328c5a833fde40f39babef4fa6
+# SKIP-SINGLE 4e6140b28324a9a63d54084c920206d00aed094e
+# SKIP-SINGLE 19cb3985a3795539b51d70625904e95a6e581eef
+# SKIP-SINGLE c52a9b6ddd9166571e6bc8bb9426b0267874f9fa
+# SKIP-SINGLE 8189b97e5ca12aff8ea34617431a868010643b5b
+# SKIP-SINGLE 0d3c57dcf3187864c0b6fd6115ee80ad33faf553
+# SKIP-SINGLE 23a130ee0d61fc39cee157921679809017a02b39
+# SKIP-SINGLE fbe6b90b0ced594cf74d5fd0dc9a32666f0d7d38
+# SKIP-SINGLE 5f3379b33866ff7dc16856b6c29712eae860af0e
+# SKIP-SINGLE 46193d5209780d21b848374d8c377fb6c8896d1b
+# SKIP-SINGLE 522f16dac945eee351cefb066af40f0d1a683f38
+# SKIP-SINGLE 1fcbd352f8116aca1ecdb62e84f3d86b89bc446f
+# SKIP-SINGLE 086c4eaf9d4ecc5074088115fa01c0b2fb061246
+# SKIP-SINGLE 37956463d67795819fe7d8fe02d6249388364783
+# SKIP-SINGLE 309b46420e83826ed1e0b947f98a47e8525e3c36
+# SKIP-SINGLE 8c0f326ea237e8acd03c51c1b3a44d237c044562
+# SKIP-SINGLE 88549ec38e9bb30e338a9985d0de4e6263b40fb7
+# SKIP-SINGLE 99af58d74e431da6b55f21272bf72a9f56ce0900
+# SKIP-SINGLE 630e2d2e6aeba60f178c6ef2b283622070b873b3
+# SKIP-SINGLE 79f017d5c3019f8bc2a5014beda28bb3b829a8e3
+# SKIP-SINGLE 78f869687e86d4a9f91003dbbbbacde2e2741487
+# SKIP-SINGLE 3ea055c90ed0b6c486518265300fa7219f8e5a29
+# SKIP-SINGLE b91bfa10413182654a76d0ba337198f39a4d0e8e
+# SKIP-SINGLE 7cc95d4d86e5a9f2df248d2aa7c8cc423c8f06e3
+# SKIP-SINGLE cb70725584a754a491ddad82c42278f17c714a2f
+# SKIP-SINGLE 0b544b676473dedf34c6cb6a3315bec1f42d7162
+# SKIP-SINGLE 8929746489bb257d1e29c3bab629b3b67e3117d2
+# SKIP-SINGLE 064541af6a71bf45d530fe34b7e00c8123ee93d8
+# SKIP-SINGLE 501ad546263ed2a902be1c9d8c1bb3af5794066b
+# SKIP-SINGLE 236648fe2623a10c8ca02637b79cd0ceffd0b6b9
+# SKIP-SINGLE 1b4442bee921d6698fc8ecac1c95c39f7ca2efe4
+# SKIP-SINGLE 8ed8ef307d9a28f6c3336a448c7fbdfe8a733d83
+# SKIP-SINGLE adfb6f1dc26a927cf4bab24bdfae54b51e3ae0ec
+# SKIP-SINGLE 6220faeb4e9be16b9dec728e72ea8dff2cfe35ba
+# SKIP-SINGLE 5ec3a58462e99533ea5200de356302181d634d0b
+# SKIP-SINGLE 04ea55fa471f0c75eeee6ccea33cf91c81fc246c
+# SKIP-SINGLE e9ec1c5b26139057f85548184ee4b47f3e29f564
+# SKIP-SINGLE ee9970734facdff57c79811a7b60973a0b9ec6b2
+# SKIP-SINGLE 4c1d7acf81a4dcec97fa4daf9e9f414e1321bfdb
+# SKIP-SINGLE 01ebe5dc0b1c71191f6a713fec245a188d587772
+# SKIP-SINGLE d8cca4d8c56a90ec9215d7bfb0b0edfa3a36ad4f
+# SKIP-SINGLE 382f6603ad4ba2a69b3961bdc68580ce77d222f9
+# SKIP-SINGLE 490fc5a5029c0d8e527a0c7f423ba83fd6afda60
+# SKIP-SINGLE cadb044fc2e69266308cdcabe6181be0f624b484
+# SKIP-SINGLE fea1ad36a0f7b1538984ab0f077095a53c570aa4
+# SKIP-SINGLE 84eef501554324b22c7a838aabed77aa79315121
+# SKIP-SINGLE 44c95c58b26b7b9d75965a83930ec3d77ffae28f
+# SKIP-SINGLE de456d1e4a1d7e34be6d040e0d8a04c42b14e62e
+# SKIP-SINGLE ce16aba66d39c076aeef0c898403e44cbfbfabbb
+# SKIP-SINGLE 89159e78bb449d3c13506a37d4a5df4424958279
+# SKIP-SINGLE 4db844a4532592ed2542c05a1747dad7ed319e15
+# SKIP-SINGLE 5b0fdefb4ca54b0d3dac3047ac1e4b380beb6ba7
+# SKIP-SINGLE c1e71d3899daca49e216dfa3a6e6e07169d02e1e
+# SKIP-SINGLE 735ae5cd3a76735c1b51913eaeff5df5f0b2b53e
+# SKIP-SINGLE e0150de010af2d9770380217f90bdc09592c968e
+# SKIP-SINGLE d22ddf5944b97ca7f853d034f9e2e812d9bf5552
+# SKIP-SINGLE 46dafe4103d1d24a9ec9b3a7a561829bcd5807aa
+# SKIP-SINGLE 622c24a2b75a564b9861fc3ca7a7878741e8568d
+# SKIP-SINGLE 6e45de6bacc508db11b15b2c8ba86aad8c0570df
+# SKIP-SINGLE 2d0a3feda61186319b7c834ee08c96926dd7ab92
+# SKIP-SINGLE 53f8f4bf2db097f4a2c68194c55a87c5a1176c8c
+# SKIP-SINGLE 2205546269bf5af01d766dc38720f71046b08dfa
+# SKIP-SINGLE e589018b48f802d69f62ab1e7e266df1c7d8cf68
+# SKIP-SINGLE fe304efa5155cd6a5c20a0731475a0ad6d087c4c
+# SKIP-SINGLE a1f93c1dfa53dbe007faa09ab0c6e913e86e3ffe
+# SKIP-SINGLE a02885a37031ec0e199dcb38ff9cb93e65e7b7cb
+# SKIP-SINGLE b20d05c6d76ddaf7e70da1430c9aac56ef1d6b31
+# SKIP-SINGLE 5317193fe55d130a456fe0cf06c56f027d617b09
+# SKIP-SINGLE 03f63888923404cd99023b853294f92536d3c87c
+# SKIP-SINGLE ea9acccd643272962831b63d932e283b8ecca7a7
+# SKIP-SINGLE 6df3eea9380f3684475e205a680804f3ff355402
+# SKIP-SINGLE 6fa9cc0593150a318f0e08e69ec10672d548a7c1
+# SKIP-SINGLE 4713dd425beac5cb459704e67dcb8f6faf714375
+# SKIP-SINGLE 2f6769f9cdb799e880fdcc09057353a0a2349bfc
+# SKIP-SINGLE 8bb5d7adaf45264900385530c7f76175ba490a77
+# SKIP-SINGLE 43c84577a3055d5ddf1f5d1b999e6ecca6139f60
+# SKIP-SINGLE 66dc8dd6d13d37ef23b52873293d95d87dca497f
+# SKIP-SINGLE 1c91bc9221d12618c9fb5507561dd35b7e392cb6
+# SKIP-SINGLE ace38bafa6ae0d40bf3fac9f998c8ecbe36d5f41
+# SKIP-SINGLE d354fc38286cba05b3ba2fefb9d9cd6d30deac3d
+# SKIP-SINGLE eb52828a439f674733ba70844b795c6673733572
+# SKIP-SINGLE 401e41df0c6aee6c071a26e0b89f16c70375fc2d
+# SKIP-SINGLE d812d20fbc3e1eff0f10443baed801adda9031cd
+# SKIP-SINGLE a3b8618d79657af0d7fea9cb6fd914ccf0f67849
+# SKIP-SINGLE 89898e43c7ceef28bb3c2116b4d8a3ec96d9c8da
+# SKIP-SINGLE 72d7961d678f9c5f4cb812e0bb9b6dffafb47c68
+# SKIP-SINGLE b1fe497a445a8be1b50c5b5952f3380ee9546710
+# SKIP-SINGLE 0ca61907cf4fe8afc723ed1e89e1a15ee69507ce
+# SKIP-SINGLE e8875bcbe067ea020dba95530ec4e9485942babd
+# SKIP-SINGLE a6b375ba4bfc9453abc428dcb73e65bfcf61b794
+# SKIP-SINGLE d490770dd09f1121b637eebdad82531de654189b
+# SKIP-SINGLE b389379c87481b6bc647ceb4d323f861281cad72
+# SKIP-SINGLE 4364a769b489c044c4e9eeac6cfbabcc844ab332
+# SKIP-SINGLE cd56490fef9cf585708b9d11de2f3f2ec1e2d5b2
+# SKIP-SINGLE 992e2019d3c535a61df064de25f664c01b8c309f
+# SKIP-SINGLE 41a5b76f79e2ef12a089e94406159e2d0e1fad1f
+# SKIP-SINGLE 3533623c4a007df80d57fe2dbc47d7e40d85041c
+# SKIP-SINGLE 21fa90b0488b2344b9b93ccc77263968d1b903b7
+# SKIP-SINGLE aca21d42d3c1327ddc202a03585416f2821e6839
+# SKIP-SINGLE 0f8343394675480f18c121520eed2203bbe1d6ec
+# SKIP-SINGLE d831312d668fbedeffe3711b13cd455309da84a1
+# SKIP-SINGLE 0c98dec5c9d0e0146a1519b9a7e099aae668c059
+# SKIP-SINGLE 491531b20d05a0f2cc747aa01e697a764c34a99d
+# SKIP-SINGLE 861824dbecc96339c68b1e15008a21c31e04721b
+# SKIP-SINGLE a13eaddce2ddbe3ba0b7f4c81715bc0fcdba99f6
+# SKIP-SINGLE 4ad6be65f68a5c875ecbaa9e66d8ced28f43670a
+# SKIP-SINGLE 2d42bf7f5e57001a836b7b4e6303fac9d3f00a1d
+# SKIP-SINGLE 2e3a33659fb85330ec76a67b2113472e7e0b546a
+# SKIP-SINGLE d0397f4a5764d3be93be3e3d35bccc1bf27522cf
+# SKIP-SINGLE d5ead735a07e619e514dd10b9e84e5d788b8a5f0
+# SKIP-SINGLE b8e0d203febffe7446cbc5e0ee7d9bf168854a88
+# SKIP-SINGLE 932698b7891668318ba9ca93375d8d27d52a07f5
+# SKIP-SINGLE 09eaf661eb6ea49c6324d8819a872c523133dc2b
+# SKIP-SINGLE 630df0587e1069b2cd2f2536d5fb61175adac3a2
+# SKIP-SINGLE edc63bf94f3cd3f52fab86fe7b92a3ec6a19de40
+# SKIP-SINGLE 47122295521c63febe9fc64680430812da3a3acf
+# SKIP-SINGLE 750721c3943e5837d7d9292d6462a144a49347c7
+# SKIP-SINGLE 1cad61030160ebc4b73e1f4212155a180d417be3
+# SKIP-SINGLE c68cce94c46140f2ad1411550427d3cc2658ec02
+# SKIP-SINGLE 8750a4546a1da4f03243df12c7e5b89f2c32d27e
+# SKIP-SINGLE 8d96feae07c618f591a952f8f10ae949735b4050
+# SKIP-SINGLE 92879a1b035baf297158812ccdbaf6ae1d157e16
+# SKIP-SINGLE bdd0c8600fcd33b6f8a535a66343591a29575042
+# SKIP-SINGLE 58430f29968a5661caff630d20dbbe7c864fe08d
+# SKIP-SINGLE f3b24e90dc9fad355102e1fdf2828ca33d447a07
+# SKIP-SINGLE 1bf7ca623b3d3e02617cf0b5f8d7f980384838d3
+# SKIP-SINGLE 0ef7f64407525a1e1bcc8aef4d1fd19a1cf60ec6
+# SKIP-SINGLE 23d3eeb798c7edc27898b0dbd4c2364a6ca6247d
+# SKIP-SINGLE 28718c4449972640c39a7be1b62ccc7f50c6e801
+# SKIP-SINGLE e6750596ef55352c260c200747bec3303e181fe8
+# SKIP-SINGLE fc05d4fec98387097c30a5c60e2f343cb797af26
+# SKIP-SINGLE 96644ed496cfc36ef886c401250203c57d77ab75
+# SKIP-SINGLE 86e512ed10d83e2d233cfb95bff68b6c05729686
+# SKIP-SINGLE a855473b7079b467ac01dbcee89cb57b3599fdac
+# SKIP-SINGLE e8adf68824178ea25a5fda0c53233a42883de861
+# SKIP-SINGLE 393228bd7a96b121f2ffba5fb7072a6cbf5ecefd
+# SKIP-SINGLE ad128fee434a954da2ead75647b6396ddbf91f6a
+# SKIP-SINGLE 056548283884d61b1b9637c3e56855ce3a17274d
+# SKIP-SINGLE aa779b0f15faa114fa5e3f59b17e628b1a837af8
+# SKIP-SINGLE cb8fcbc3cbd8f6cf95bb858b72188d752672cf6b
+# SKIP-SINGLE 0397f85c6f9b0a5325f774e2a56e7cd85176e228
+# SKIP-SINGLE 22fc91704be4737865b3715e5278dc78029791bd
+# SKIP-SINGLE 6d58dda40a0a43d14dffdd995f0cb3dcc329fa4b
+# SKIP-SINGLE 5772b920f40a8c9f0a5266caf8d0f4729f6d2c13
+# SKIP-SINGLE b104d764216026d77680a79993a051725e5ab94c
+# SKIP-SINGLE 89b5a8283375f83b8f0e174a3a8760158b99be6e
+# SKIP-SINGLE 1784ce6080e4895a48ce71747a136d9642baa73e
+# SKIP-SINGLE a3e9694078e24d19db860aa4ff8dec8bc34b59b7
+# SKIP-SINGLE 5e47c2e52b9b7616668c5586084e0128b231272a
+# SKIP-SINGLE 7a762fbbfc1c05be8de3d253251f5e7b32da2c73
+# SKIP-SINGLE eebb9783e1674732b7c63d50211b524ff0fea7bd
+# SKIP-SINGLE d533f5f2a783e4c6448f841e709f4528f498b7ea
+# SKIP-SINGLE 85f6aa33f55da97b13b5e81616f16a517d24f3d5
+# SKIP-SINGLE 59f3c86659c061e2673eb0da0bc78528d30f8f76
+# SKIP-SINGLE b91455633b03add918af3eb166ac797fd6c95722
+# SKIP-SINGLE 6c106712a8d2ffd0c932541cb50cc59a6df732f4
+# SKIP-SINGLE 65d428228bb57ce434a8eb5a4eeb2274171586b8
+# SKIP-SINGLE 4219240e1df6abbd842f4474fe7862f341cc355a
+# SKIP-SINGLE 6f6639d6ed6c6314b2643f6c22498fc2e23d34c7
+# SKIP-SINGLE 633db417fc3e905b28b017facdf596b36914b44d
+# SKIP-SINGLE 28e6584861a7f80b199edcd0d9eb3d97e344958f
+# SKIP-SINGLE 9b4b2e9fc8dfd37ad8f44940a16330c477f896ea
+# SKIP-SINGLE c3ac93bb9ff8b1fe1fc32f99c725e6cc209aa6ca
+# SKIP-SINGLE 885c512603f946dfb7a45c181e94b8677be2678d
+# SKIP-SINGLE 2cb9805702a4f15ca7ee4ef4edb6e6048b1d3320
+# SKIP-SINGLE 66d37175ecac41dfb2f854dbb148dcc7ca87b345
+# SKIP-SINGLE bb47c72de35312b742a1964b31ff315727baed00
+# SKIP-SINGLE 2c39565dc046d428127735552db6e7814631d4d4
+# SKIP-SINGLE 3c2e8eff8cc9a4a535f473b3e150cb056d8f891d
+# SKIP-SINGLE d79cf638f278e50c22feb53d6ba556f5ce9d7853
+# SKIP-SINGLE 06e452a57287c797cb96a6d4b45220358daab379
+# SKIP-SINGLE 85b4e88194cae541a0093a9166f4306e6fd3109e
+# SKIP-SINGLE 9613690f6e51e2f2aa2bcbbede3e209d08cfaaad
+# SKIP-SINGLE 6735df4443fe0aa60862a95c38746edf2b053862
+# SKIP-SINGLE f07c325d1f49e4b722f76aa730ac5d084bd0e77a
+# SKIP-SINGLE 151496a4b96430924bc148f85b9c8471d1e132b1
+# SKIP-SINGLE 9793a4616833a26157b4c60278ec17a9be233d8f
+# SKIP-SINGLE dad1aeb30760ef524e95e636c22346b051233a38
+# SKIP-SINGLE 8ba61ffd8cebb0ff9f7a219022f3c1f3eac2f6d0
+# SKIP-SINGLE e9ca57cfcbaf1a8dfc6bde5a2afd5f3c7b357cb1
+# SKIP-SINGLE 682118f5a06eebdc38767047e65d42aa9356cfe8
+# SKIP-SINGLE 2825d849451be45ea738e2d2b2567c834fe5a0fb
+# SKIP-SINGLE 0263216ec39d0914f17b662a3e45b4163ab6cc78
+# SKIP-SINGLE 3ba07bfc3ec43aa10d8e2d06a8f36f7022287573
+# SKIP-SINGLE e442879b5a963a6eb37403fe09f476e7ee8e0f55
+# SKIP-SINGLE 4575ae5a9c5589ac903362486951f0d36c8ff8ee
+# SKIP-SINGLE 67afa75e2b97c08976f0e5a8502dac5851d45f93
+# SKIP-SINGLE 64eb2fc74013a221927f9bef920e367758e1bc15
+# SKIP-SINGLE 37dd95866a004a9db1d77f075715243246033773
+# SKIP-SINGLE 8af26410a91c3c9679bb0281ddd71f0dd77ec97c
+# SKIP-SINGLE 76715f8921dca740880cd22c644a6328cd810846
+# SKIP-SINGLE 678881e428073b39a906c1ffd01e1b76e271cb5d
+# SKIP-SINGLE 155ec5096928ddb121fb725fca65436d6353cb67
+# SKIP-SINGLE cc3d7580fc1cab3119e5e05c427575a2668cbb4f
+# SKIP-SINGLE e2a78b0d6d844f29acaaddd775c7b1cd6dec7af8
+# SKIP-SINGLE 45eb3b3513619d97d046a8efbe0d16fafc75a734
+# SKIP-SINGLE 27980e36040d0693fe997de6b6b73c09c3ce1cb5
+# SKIP-SINGLE cca0e79ea81712786f92a6668c61001e60d24f32
+# SKIP-SINGLE 3dea8f8f53f81a1d15a55c9e3c87a7eade7ca273
+# SKIP-SINGLE d0fac17abdf6883bbf82b1752988db38d05282e6
+# SKIP-SINGLE 8fb995b9e360270b6a4d7b7732a127a6234eba23
+# SKIP-SINGLE a770fb44288c75fa2b0471ceaf00bf741376e40f
+# SKIP-SINGLE c7e393bc4130c871a92fef7e9ac0c7c1832aa614
+# SKIP-SINGLE 0d868917efb46400cf7dd57a1cdbba7404f322a7
+# SKIP-SINGLE 025adce2cf43f4ce9f3c543c1b8973541e1414d2
+# SKIP-SINGLE 872faabbd8cb0f5518777b2d4fe7de187f684a92
+# SKIP-SINGLE d14808cd271abf6a723bf495a6a01c14d18b5893
+# SKIP-SINGLE 23eab9a6a67604b5ebcdc99efc42fbfd3345c0b0
+# SKIP-SINGLE 6d4bf2cedab365411f0aedb373b63291086658e9
+# SKIP-SINGLE 5875fbaa2dfd919a2ba22db1d20ffa6c4c6e13bd
+# SKIP-SINGLE babe0d4508273c5fe0a3228b3d2b4d3dcb72cd58
+# SKIP-SINGLE eb83344fc7c08ec08b51e7700f1ac2632afa462c
+# SKIP-SINGLE 5c3dba24ef5f40825a01e30d2790c66df202b8b1
+# SKIP-SINGLE 47b7a5bd492e92dda928843e28a707b9682cb32f
+# SKIP-SINGLE accb7b7ecc19f85c2750ded1046a464bc73c6a52
+# SKIP-SINGLE 10a45096988f6f19e36e2e7865b6eb35c0929b6d
+# SKIP-SINGLE fe859a07870d5204adfd5c9a7f83bf69658d37c8
+# SKIP-SINGLE 61f3a4b4fcc43241caaac63195205774ab1a5732
+# SKIP-SINGLE 410e65e4ce6f871fd1b8a2ef4b227cbeeb17c1dd
+# SKIP-SINGLE 4fbdccedd58ffe4cd5f7ed7b744123cc25084bc4
+# SKIP-SINGLE a9140091dd0df7e89ddbaabec17608a20f06f7b0
+# SKIP-SINGLE 0c9bce3fc490d6f5e935883e9690871cce4f9150
+# SKIP-SINGLE 6c560a3b16f9015a19044395f0ef41b718d73496
+# SKIP-SINGLE cd06d173a602bf0aa8a227ff1626dc70013fe480
+# SKIP-SINGLE d1ea675d2cfccfb043c8e853c410427ca62dd921
+# SKIP-SINGLE 5e841bc9e5ff878b3dce36a712386ed6f53b6e60
+# SKIP-SINGLE 284f635da833d2dbf0102af3442197b46adf78c5
+# SKIP-SINGLE 41e20ee4bc01576d23fb8fd4f875385ce57eb36a
+# SKIP-SINGLE a411517faf624657aa58979f5463115115093309
+# SKIP-SINGLE da9541dd1086b7bab52940c82915efe114bb7419
+# SKIP-SINGLE fe6c507f5ce0fd744b5bd1d0db6ea175e1188a7f
+# SKIP-SINGLE e08e0880f9892fba747abdb95b1f3382ebd17e32
+# SKIP-SINGLE b6d8d34aede02a6af7a614f32b86292ee4ba1757
+# SKIP-SINGLE c4bacb1215bfdf058b374312256c27eaea1304a4
+# SKIP-SINGLE 534c33cf375182c97291d2dd242f936df5953321
+# SKIP-SINGLE d8a6d82c4d34286b377fd7bddd4be0116e8dd4b9
+# SKIP-SINGLE b3df3729596332a39404c364798a61bfef2adcc2
+# SKIP-SINGLE 134edc10367a8434167656e631865c85b5f10c42
+# SKIP-SINGLE d3a0ddedba53b9e2c99274c8ec125d53f991da5d
+# SKIP-SINGLE 4498e5a13a3b63a3024ceef102ae3b5c50f58be1
+# SKIP-SINGLE 9813905f834aa43eb194023f579c7e7951d96d0f
+# SKIP-SINGLE ec2e5a54b3b6324f1039f355fa646034918f6dba
+# SKIP-SINGLE 4a04046b7200b9c7201c252c23a8c313d4687b5f
+# SKIP-SINGLE bfcff8f88a472bd1a64922da094cd007d3b7a70a
+# SKIP-SINGLE b552fc05c231ca6800330a318d3a74ddd0f5a13c
+# SKIP-SINGLE 01963fbbe10d290ba037cd523d21ebbcd2536b40
+# SKIP-SINGLE c31823a51bba1e4f0c87af1a08ce856cc600f5c8
+# SKIP-SINGLE 66c388c21aa83d3ddb5a1827f81dd432514242ac
+# SKIP-SINGLE 77b1148b5164c71c4ba673173eed2a37918d4f78
+# SKIP-SINGLE 63091313490beee4c5ed9767195c2a3df98f0332
+# SKIP-SINGLE f0c0b2cea3ffea7e3c53ff24c58e7a08ac40babb
+# SKIP-SINGLE 1ac5c6c3cfc4c50347af893aa72926cdf2edb8c1
+# SKIP-SINGLE 926a394997eaae55b797a90cb2cd037bbe3c3db4
+# SKIP-SINGLE 31c60dfbd8541c9f1b1bc8127dde85e5d5af51b5
+# SKIP-SINGLE be3ab9f301bf741b0410c1f9fb1c5ce6dda1c39a
+# SKIP-SINGLE 4bfde2a79046519815e2bb8a8eb72e22eca0641f
+# SKIP-SINGLE 7bba702e1ad1ed343618e44cf5bbc2a1f079be0c
+# SKIP-SINGLE c64cb02cca320811032bb300ea6d12cf59acf65d
+# SKIP-SINGLE f208d5ae77cf381c6f1db9b1aef76d5e9805a106
+# SKIP-SINGLE c113d6f3c1e12fed3aa627e74a2a43be0350c31c
+# SKIP-SINGLE fa3af359df8754423a197682d31245ad88c02033
+# SKIP-SINGLE 6fe661342a24edcaea255c3ba9a37613031554da
+# SKIP-SINGLE b93e5463885f9c99e74b52d2f569ad06ec2d0ff8
+# SKIP-SINGLE 8a11e430ec261c08cc928a7a5b05ee1027f50368
+# SKIP-SINGLE 699fce296b13d7db386b1cb5cecf2710e5196691
+# SKIP-SINGLE 698ff554ac2699ec48fefc85a1307cbc4a183b0d
+# SKIP-SINGLE ab9e58b8e39f19cb35513f77310141a344a4de15
+# SKIP-SINGLE 648fdbbcec159e6bfdb7cd06d32c59e8a17a055e
+# SKIP-SINGLE 52e17e53b7dbafb4877d98d99188c335db6a3b5b
+# SKIP-SINGLE 394282142563fe1341eba1845672e2412bf8c7d9
+# SKIP-SINGLE f0151e17d296bfdeb1ca3f002c9b430c8302a6e7
+# SKIP-SINGLE 90c25b245259e99013dfb9292bea054a0ab4ffb6
+# SKIP-SINGLE b26c2767edd98787297879c4570a2702eef031be
+# SKIP-SINGLE 8c17995f7f948955c765562f32526d0a3b87398e
+# SKIP-SINGLE 093f5d0045cc5facd3728e385a71ef84f218bdfe
+# SKIP-SINGLE 18a7e5414c534db38eedb06b16ef68f2c17b98fd
+# SKIP-SINGLE 34f01eb88f87fb8bd5b816d76a2527b5277862a7
+# SKIP-SINGLE a1deb6cac305a73e799c63e2fbfe7221790e1e61
+# SKIP-SINGLE 58a3c54c7ea86ea6b715483e7b017008a78fbf14
+# SKIP-SINGLE 2da3305c3c335adcbc9e541b7c50e4e814df87d1
+# SKIP-SINGLE 2c5a3f413b7477544ba8f5b18ed233ea6ab6f2aa
+# SKIP-SINGLE 45a0ce0905e495ae93b39e75cedb34ac95c6ea71
+# SKIP-SINGLE b67a6cb8dd7f8e6757a54f1547f631f26fe26e74
+# SKIP-SINGLE c2e27949d5917256bb419dcdae73566079844b4d
+# SKIP-SINGLE 0701634aa788b316f331ccbb6c44dfd8304a271d
+# SKIP-SINGLE 8b379bbeca9b3765e2b1e948d9d9c90ab92ff4b6
+# SKIP-SINGLE f6ab713bbc3dc8fccf5fe490615aa2b679071010
+# SKIP-SINGLE a7f71e8dfae9b1571a2ad34e44f000ff4a391644
+# SKIP-SINGLE f21ec24524c705e18674a2e9e4db37b11fa3ebab
+# SKIP-SINGLE d715ae8788e16b22f7f68cb82b51a40ad95c78c2
+# SKIP-SINGLE 7bbb56bc430465a6807a8129a322c704c89e3eba
+# SKIP-SINGLE 7f6b0c1ee93663892c6220b982f7bc3275dcaa85
+# SKIP-SINGLE 18c83aedd91023a677153abeafe561eddb430146
+# SKIP-SINGLE 68b8980eee5683128035800d6a04c27c764fcc5f
+# SKIP-SINGLE 26577415400b88c66add5ac8848e6e370739bc21
+# SKIP-SINGLE 5b525f4f56f458d88b66be73cae2d1fc5b382db4
+# SKIP-SINGLE 9fac0e70e3f5b7d0b12b77cac50078e01f68ee70
+# SKIP-SINGLE c717a5bf53a9f08f2123968b62800a8450589719
+# SKIP-SINGLE 73ab8f4b8cb6f08e7b694bdadcd42751b3916dae
+# SKIP-SINGLE e2e63dc3f062ec3dee56f003efb3e093b56692d4
+# SKIP-SINGLE d16b73fb4a9d87ec220444d220c6b45879806fc0
+# SKIP-SINGLE 982af7f516efb190d19946bff7bb37567328b4b9
+# SKIP-SINGLE 9645b5752a3e40754d22d9e805778e95fdc86337
+# SKIP-SINGLE 1743da11d0fdbb24f6c6e8d084e98d0b6e4d3f62
+# SKIP-SINGLE 7556772ac2e375d3812665dd8e31548e0dd1f7ee
+# SKIP-SINGLE e4636297c630a81e1e201210b4e6da7e99b823a7
+# SKIP-SINGLE 5fb3782e95d512ddb9a23e7d713de5980c7c4c2a
+# SKIP-SINGLE 7e911d007d25df9a483eaad54956a4273405574e
+# SKIP-SINGLE daf32f1f87b3d71cddd9ab2e9e4c3f5b523ae409
+# SKIP-SINGLE 0dc5a85a1c3772a6e78f077719d82f437f626b1e
+# SKIP-SINGLE 0c450e09b8eea8839d10c329debb3be37ccd9a34
+# SKIP-SINGLE a7aae1473c1aed7758b550a23cda61ee17668e23
+# SKIP-SINGLE 48daf77a9d963c05ee198b3ab108c7f0b3686da6
+# SKIP-SINGLE 8f522efe9a963cd3523ea6863f9bd44881cdf6b7
+# SKIP-SINGLE b82f34f996c25deda1b89fc7006833335bb1a6fa
+# SKIP-SINGLE d38110efa75372d4c3be702f157d3a8c6b7f37b5
+# SKIP-SINGLE 30026cfe666e9647aeef73e26df5ffca2fa2c662
+# SKIP-SINGLE dff4f9c759f5cf19047719716ea5ee8ffdc3006e
+# SKIP-SINGLE 6eb122c8db9d6a445b2002f025e01215ab560843
+# SKIP-SINGLE 79a01866a01754b9f566af76ef96e80cd90d094b
+# SKIP-SINGLE 34f1035e878a06ad181ff7fc533cd1fa0a565847
+# SKIP-SINGLE b478444099655f36f7b243e21e8f98051299ca8f
+# SKIP-SINGLE feae2de4242d7288f94c4bb41a9b7deed8679da0
+# SKIP-SINGLE 7fc0292f5c49d11fc39853f8bc25586d54221e6a
+# SKIP-SINGLE 278b7c1b52be11e8c49b8252953e8e84d45765c3
+# SKIP-SINGLE 2385dddb3338fd0f34aac0633dde78dd650f7d94
+# SKIP-SINGLE 5ea28ea4d12140ebcfaa293b6f29521a80b3de25
+# SKIP-SINGLE 981c309325d55e8c5947274e4df6346ea51a056a
+# SKIP-SINGLE 11c3ec3df6ad79ee5175094f0cf14248d9724aa2
+# SKIP-SINGLE 21f5bd6154f254a53942a9823c9c708ffa4b22a4
+# SKIP-SINGLE 9a56b9bf71af83292d6831e08a8179b7cf5ee7d8
+# SKIP-SINGLE 120f691e99d7d98a959ec9a6075cb4e473831bee
+# SKIP-SINGLE c4fcaf5e729fe5ff9249a56b1d0f5927ef3932a5
+# SKIP-SINGLE 9aa13cd4beccfe41e8f4930cb029bd60e7788e93
+# SKIP-SINGLE 8aeba640460adbad283d4a18f91cce8e0364c40d
+# SKIP-SINGLE f521225736b2a6ab38bb94298fb4d3ace3d9a9ec
+# SKIP-SINGLE eac531b760aa805c293339eba78e58b5b89fa211
+# SKIP-SINGLE a590a8058d52c1cbe0f80b7ed0d8b0abed7bf7ef
+# SKIP-SINGLE f0f2a53b27187903c86189bd03f072ac6ddaba9c
+# SKIP-SINGLE d8c2da46e7e51a11882dabd593af29f4146aa0b3
+# SKIP-SINGLE 7844846e3fedac8f32f0d81d3c5e906715d39fd2
+# SKIP-SINGLE 3886a5c140b03f07c8faea7cacad0a791bc54fa5
+# SKIP-SINGLE a397fa06d18d6ae37a3a1288f269e1ae9eb3b569
+# SKIP-SINGLE ad33e3e549e24c48259c6bdfb069e41be0a31f98
+# SKIP-SINGLE afe4969a3b3b38014387a828b66f5dbc3a462a57
+# SKIP-SINGLE 5c74b806a6fb0a4cb237300ab0a5418a109ced5e
+# SKIP-SINGLE d9c6b4378ac851f5e730daa0ae36c9ee2d0292fe
+# SKIP-SINGLE 7362554eafd7e255b3d96a4f711e11708dee950f
+# SKIP-SINGLE b293aa91bcc7f553ffbc6c67027f3c86d06ffbd7
+# SKIP-SINGLE 232a36f17e2796c52cb0b1afd5872c454b92ce62
+# SKIP-SINGLE c4687d920db081f29e93cca8156793d545a827e2
+# SKIP-SINGLE 3fc859d9550ff6d35dbb453eb75c3296f23a94cb
+# SKIP-SINGLE 11192b29adf4ee500f5056d1b02d35908f858b53
+# SKIP-SINGLE 3ba1b52e277261286738b637e45a675b7d587f58
+# SKIP-SINGLE 498468a2367524c7bd763826df5aad2b76345912
+# SKIP-SINGLE c4b886831acb82643a38f48c91456b15363bed75
+# SKIP-SINGLE b18f92a942dca6f95c9a74835644e482f3b1b907
+# SKIP-SINGLE 6c77a9e046de682aaace72aaf3af78e6ba9e5489
+# SKIP-SINGLE 976b7fcc8ced57fa12a0504899974b5b2057c943
+# SKIP-SINGLE f0290502f3354f9ed7e8ec84c24ac13a7bad2fc0
+# SKIP-SINGLE 4946ed48fee637eba75b674b9ad568b9df26bac9
+# SKIP-SINGLE 2875340c9fcc3bd6a799a3c4a4d875fc753ea7b1
+# SKIP-SINGLE 037b9897a464bf25ef9587ee860cc7f20376a97c
+# SKIP-SINGLE e666bf781f1d3d74068e8d2b505e35dd75b5b423
+# SKIP-SINGLE 00f7fd7d427b85e69a53403a1d10ac122a92a95d
+# SKIP-SINGLE 0bb5a47402313634b0e8654355e519388851e07f
+# SKIP-SINGLE c00236a880567c72dcdba5fc90d6de1125616c76
+# SKIP-SINGLE 1c08dc82121d50e80bd2dcb0d1f39654cc6762dd
+# SKIP-SINGLE f4cb9cc9034c09a8798df3d98f6fa9313a777a96
+# SKIP-SINGLE a5a1b53807a9449298f62c761223e6a1c5654bf7
+# SKIP-SINGLE 92e285fdf0821d8a01db598c4e2ac7e2e0fbb3cf
+# SKIP-SINGLE fdb31d6a2709bff751c2ad240c41b30db1848b44
+# SKIP-SINGLE 9514dbf7ed70b6c08a11fd58c7889ff49e30ac13
+# SKIP-SINGLE 4beb850efb99b881fb8b648ad7bb43c6539a2431
+# SKIP-SINGLE 5f63ac26ccc18bcf9e364b74af4424f9e3677cf8
+# SKIP-SINGLE 726d8c5bae847a3240b758a1d25135865e9304f0
+# SKIP-SINGLE 44db9b912f1d8165383b5b30732fa9caa3d3a185
+# SKIP-SINGLE cedc19297e47473ae599faa7cbcb2f3f6c9d5846
+# SKIP-SINGLE e678021f0c3db705c91831cff466561fd73c3040
+# SKIP-SINGLE ef59b67e4657fa80d1528b9d476c67f01abecc35
+# SKIP-SINGLE 2ccce1bc3954ce5f2faa0dcf7fa68ec5cae710ca
+# SKIP-SINGLE 568883c9be8bfbb15ea48ae0de2c117894e8db4e
+# SKIP-SINGLE b6d6e7feb75b792c74fe3e1d036b9edf540d771e
+# SKIP-SINGLE 15ac087712250b5ffeb4d162761b2495a5e572a3
+# SKIP-SINGLE 36ab5c6d49f8fbfb858844743223414e6f2f2564
+# SKIP-SINGLE 080dacda7896e0eb5ee54b1550097e45a4f423de
+# SKIP-SINGLE df62baa7d4e8ce0760f32122899ae3c803180907
+# SKIP-SINGLE 8b1d9b8e5ed8035bd2f42517bb6bc3c8a6d6f0ae
+# SKIP-SINGLE ca8d5ed6ecd5ca3eafa2923ee04e56dc474bd964
+# SKIP-SINGLE df0a7547cbaf19152a74b5dda760e5d1f6c92ecc
+# SKIP-SINGLE 12639610f78f9006b70933bfc6898c1312f95290
+# SKIP-SINGLE fd3c00ff92826b466a3292a05072eb5b4f23a701
+# SKIP-SINGLE 0a74771ee9c406cf98d391378340c79645c88d52
+# SKIP-SINGLE 5dae0a9a55101aeb668f90e1fece1ffbab5e7ee2
+# SKIP-SINGLE b275ddd63a24b15dd8f90ea0c4f27341a8dfa977
+# SKIP-SINGLE 5ecb71c1e65038b79933c06e1c0303b3e58ef4b5
+# SKIP-SINGLE 42362d991443689162c3e0bf1eb683a85481a391
+# SKIP-SINGLE a88e5f0f199ad018d57d07016dce20e5462dbbca
+# SKIP-SINGLE 4c8b46514d87856e5e2044bce804ad0156097d04
+# SKIP-SINGLE c5bb62f99db4b1c70e68e7c7a30ede8227f199a3
+# SKIP-SINGLE 79436f0c744a65ed2757f0119f5bd13e2fbef995
+# SKIP-SINGLE 54677f96f3ad8e489e04c8bc7875e1ec4d6b9a79
+# SKIP-SINGLE 9a8f33f285295daff8ed02d35ece5e8fe11ac887
+# SKIP-SINGLE f0671c60637e218a54f9f3ac8e5950d17884f50b
+# SKIP-SINGLE 4496a3f5ba899c89e45cd478a22b25ddf77869ec
+# SKIP-SINGLE b3cbdfc86474932e4ef8d1237ed100a6f4f4c854
+# SKIP-SINGLE a647a97320e72db275a05961ae09e487ee3063e2
+# SKIP-SINGLE ee4feb005ffe1d35ffc4d390d18b88ecfdebe2c2
+# SKIP-SINGLE 88671e638b308886a9d6b5a590ee1aee56746d7b
+# SKIP-SINGLE a10405386f83333184c94a0a194b404e4273e2d0
+# SKIP-SINGLE d0fcb15fa9858eb600b0a8f35ebbdf5aadc2cd7c
+# SKIP-SINGLE d0173ecd0ce8c2ac458cd84c25216f59f3fc9889
+# SKIP-SINGLE ac08a7f26c53d65df7d9c2a5d76300a6a1a8106b
+# SKIP-SINGLE 694ece772220346aef12520bc66ca401d08809bb
+# SKIP-SINGLE 740462da6153b111a8196b003791a55c7f7fa878
+# SKIP-SINGLE 8234a62e6fb9f706f410a96e2ce9877c19e44a20
+# SKIP-SINGLE 26ce5664ae431ec141e852a4183844d83c3f8856
+# SKIP-SINGLE 54e0b112d3a91c86230bc4329e00ae8f2faa05e8
+# SKIP-SINGLE 6c9acd13d0d2aa181d21bf78d6530b3399520533
+# SKIP-SINGLE b3db331e8c36ef9706ad16c12055079bcd93c022
+# SKIP-SINGLE 3345399e87fe6100ef82c399337760ab01182240
+# SKIP-SINGLE a248dfe2c3341ed73de38c2feea64ec12f053aaa
+# SKIP-SINGLE 48f5530e7922e4c46db1c4ab82b1c3532db724c9
+# SKIP-SINGLE d7071c64575bd3116e154f93915ff099c6e0f3a0
+# SKIP-SINGLE e2855d93ee41bf23a72fdcb49bd5347512989f6f
+# SKIP-SINGLE f4de790beec514808eafd1cb22fa5eacdecd4552
+# SKIP-SINGLE e05253cb9bc4a35c7dedc3cbb2830e37d385a339
+# SKIP-SINGLE 60a81f44e49c77ef9143a665f94f89109002133d
+# SKIP-SINGLE 4a639f3ae9594f0d16835d5151b6dda7e83e1a1f
+# SKIP-SINGLE ce254ffa44e33352605e49aaa7d5fc4f545c1add
+# SKIP-SINGLE 9a87c4404fd0097e2efa14f63b97a9df8df6c07d
+# SKIP-SINGLE 7f5f60d54340aa0b36f22057fd3f2665fbcd5d67
+# SKIP-SINGLE a214a29e48397cf259327e1ffb44479648301e47
+# SKIP-SINGLE 5411beae0225937446eb8509c56277b120a2eb92
+# SKIP-SINGLE ba51c31b47a62e6815d8cb2cb34ecd642a677105
+# SKIP-SINGLE 10adad440b2eb3b09d9d4e876023dd13d8b3dab9
+# SKIP-SINGLE 6a3624eecbc0a116b293d05e044b8b40a86022e9
+# SKIP-SINGLE 44023f3db21c0365ceeb179657447d7cdb1feb8f
+# SKIP-SINGLE ba2bbea816ac5a20fa3090b634a17ed0d4a1c2ca
+# SKIP-SINGLE 9650e5a1a90768953ce9f3eef014616180bfed8e
+# SKIP-SINGLE 831f5e606125c48f783daee9643d101b7fad665f
+# SKIP-SINGLE f0b1519fbd0fea728238758d6bec074c32be1142
+# SKIP-SINGLE ea421cfefef6826dd99a9cc884b46178b2c0e1a8
+# SKIP-SINGLE d4a5aba954c838b32317560dd84e6681578b0e32
+# SKIP-SINGLE d2d229043674c59dead9a58a9ae20f8e62427fc1
+# SKIP-SINGLE 4fc8524df0e2ce0579d6bc298dc07d1e442587c6
+# SKIP-SINGLE 0c94e69fa6ed5a4f5d551f37f7f2632d2f2b2952
+# SKIP-SINGLE 960aa0c7985f6c61a26f99653c6e9ae9369e944e
+# SKIP-SINGLE c039822082983d6618b6e06c73a31cf6b63467cc
+# SKIP-SINGLE a421c277237ab6b5923473f6dbb9c196b16bc833
+# SKIP-SINGLE d901221e2bb2168cd1f05e3b2355e078c45f1f42
+# SKIP-SINGLE 954eb9b4a0b9d616db9646f081d11b2c6dd19581
+# SKIP-SINGLE 8ef0a1814eca5dc7f32e2784b3fa61498d220a70
+# SKIP-SINGLE 99258421bbb123e6f277610dcf94e022dde3a5c0
+# SKIP-SINGLE d0e6a276643b2590eebf81e305b006c768653b10
+# SKIP-SINGLE 0bf55d3a8131da02999fe694caf34096d7408952
+# SKIP-SINGLE 71b363e2b3c709e64f8ef8ab7446cc3a19573eeb
+# SKIP-SINGLE 23874aee8825a6f670b6c2da9eca2d9cf643b3af
+# SKIP-SINGLE 4fe02acb6b0556c4b17c7a8e01f41698f5109512
+# SKIP-SINGLE 95eb82644d348c59af9f4ec10ad315bf5e498353
+# SKIP-SINGLE eae7f30a9a338b5713d7808c9f791e1a7f79b3cf
+# SKIP-SINGLE 630fcab4fcfa9afab4688d803892d76cf6f46961
+# SKIP-SINGLE 37989f9431bc32f7ebac76cfc02f5e1d03486bcf
+# SKIP-SINGLE e97826ab845597fe09be43b2df888e96c7502bee
+# SKIP-SINGLE 0c60b3bae71a010e6abdcfd4d8d38b92c7874609
+# SKIP-SINGLE ab5611c25b92ca06238de3d0ae53226176c2ae0d
+# SKIP-SINGLE 407f5aac70f1481dfb365db7ba2e435f439498d0
+# SKIP-SINGLE 3681402bf163a3b5a7b7642f553e87693028649e
+# SKIP-SINGLE 16fe8a4678d20eac893bd05941071396b67bc84d
+# SKIP-SINGLE a99a3fbc40076aa3965feb759e816a8a25621c6a
+# SKIP-SINGLE 42b08f8a9ada7791c992894e88f648909e1ecc95
+# SKIP-SINGLE 41bfb91f5db878d139d5c0c631c569475018a7c2
+# SKIP-SINGLE 77c9236957a195a4ad0f50e8f19653a5c6918c8e
+# SKIP-SINGLE 41e5c9400cd9eeeecff2262907c09c3b10a5cde7
+# SKIP-SINGLE 3850be836ec7223c895901dd21f2a4e429314b94
+# SKIP-SINGLE 065dd0b5c6a7e11e79fe5ec02b153bb53bde0e77
+# SKIP-SINGLE 207b15147366be47d58c40a6f03888243602b11e
+# SKIP-SINGLE 6a546e63d0134861b208ab1bac259f71fcb30b83
+# SKIP-SINGLE f6b58e8016c7ce7b332a3b2a8a56bd2f9987d95a
+# SKIP-SINGLE ab3f36fac2da2979713109561f086d95bb26d580
+# SKIP-SINGLE 437c75cfcda4a0e9fd387d22aa8c0177c835c66b
+# SKIP-SINGLE 13f3b52fa422bed85fd7d50b43a167bb011e9070
+# SKIP-SINGLE f7c52087b2a836ab8913b7718ad37230a2895ef3
+# SKIP-SINGLE 3d0a3a51b8f1635ec872fc3f0a54c2d58ba48b4e
+# SKIP-SINGLE 76fcc2a69a96a7ab68b82ebc96c234dd58ef7e61
+# SKIP-SINGLE a82f1929fef5072a4b04e326b467cca8a8a21c0e
+# SKIP-SINGLE 4bb671f1c6adb6cbdcf90abe73967c24e5296372
+# SKIP-SINGLE 11b34169f802908348e99d0a52b9c50a64028964
+# SKIP-SINGLE b91cbf80aeb4487ad3e1fa0e64e3cb5549ec663c
+# SKIP-SINGLE 787444c7690d97d8702db059cb51ac506cb8a5e4
+# SKIP-SINGLE a1fd3d6eacaf425eadd121dcacee95a26f96505f
+# SKIP-SINGLE 0f526028b1830e72df1c39220c5efdc7e545885b
+# SKIP-SINGLE 9b44051ea530247e73dbc0bdc2998d2dbf9688c1
+# SKIP-SINGLE 6317f9e7b847f83e6a6d0f9ce9233a0566d84f0c
+# SKIP-SINGLE 0f59ce58fc558643f97175a32f2a82cc209f2bb4
+# SKIP-SINGLE 06fc663f519eefb431912ebdae8711ed016e0703
+# SKIP-SINGLE f59a96f5655c0ac2846a06cbad11ef3039476fb0
+# SKIP-SINGLE d8f3f8736c7d36b220a478f98deae9f82f25a4f7
+# SKIP-SINGLE 8b8b8539d7415f1decde46d088c89c2fc69b1010
+# SKIP-SINGLE 4320307843b44fa049ba7e8217f0349932ff56e5
+# SKIP-SINGLE 0cf4a9fdfc63577c97ff0d0e46f49cd685c5291f
+# SKIP-SINGLE fd42b6c696564cdb44999f6d4d3f91a63799191a
+# SKIP-SINGLE 009089f0d69a26e9779628e5b9c1d139eddf20d2
+# SKIP-SINGLE 7c9a3556e3d66c1ebe75f675341117bb28041da8
+# SKIP-SINGLE 37a04737218281fecf7b4e8b9a58839e25f02815
+# SKIP-SINGLE 3bc77cca86fbed8c12fb6c10c51e1237d65c9143
+# SKIP-SINGLE 13816f14b2f459a97d309f202f218282888e9bc9
+# SKIP-SINGLE e1128305102bab268272770b4a77361dcd9efb5d
+# SKIP-SINGLE 942702f506de1c7c3eff4e13470248be1a26e778
+# SKIP-SINGLE 00c493f01703f619a62e08bea17a49ce12f2367b
+# SKIP-SINGLE c9f367950652a3728cc94c7a7faf0aa55c2aae9f
+# SKIP-SINGLE c33c2ef5119a3e1ba9c97ca03e001916f83d09f9
+# SKIP-SINGLE d5ffb4949044ae58fb418b1b214cc7c6eb16a29c
+# SKIP-SINGLE f9ea53442e6f492f1543a5e21479e72be8eff4c3
+# SKIP-SINGLE aee75b87719abfaed605e33ed0c9e3a9a81417d8
+# SKIP-SINGLE 76dd30a98590f2266290a70f2e3d4d272c092310
+# SKIP-SINGLE e176d04d45adbb51f6bfa0b5a0352927056f3519
+# SKIP-SINGLE 26aeca29801a8e8950141d9d54aeb9a22ee6c5ad
+# SKIP-SINGLE 2ee2c67736cd76a52a2eb1002d0ec15e883082e0
+# SKIP-SINGLE 105e7180230dc22db91af2c8cbfa6fc3d2fee7e6
+# SKIP-SINGLE 3ed524c908d4aefd174ae6a8adc2bdaabb4bc4da
+# SKIP-SINGLE c47892201b2b9f1ef903ff2a12bb9ed9e64d19de
+# SKIP-SINGLE 6d230fc2c04532b4abf2474411b2995c237d5cc8
+# SKIP-SINGLE ce4375f57f9b89d68fb639590f3e4a0a28e3a627
+# SKIP-SINGLE 6a34ff5d9c13688a7264b2654f04982c5a3cfc6b
+# SKIP-SINGLE ec00ef8d48afaef65527c02ea013ba4489ed279d
+# SKIP-SINGLE eca71dd5c7a8b7013eb20e1457eddf62776e6c29
+# SKIP-SINGLE 6761e69a2bce255bbd78e08b5c592f4de19253f5
+# SKIP-SINGLE 93aeb781e1da3cab6ae90c90cd3668862155ab85
+# SKIP-SINGLE f97c03ebca440229ff953baee9e458a3ddcdaa70
+# SKIP-SINGLE 33d8b736b0330f51050ca1fc389527d708b1eb23
+# SKIP-SINGLE d392276b63cd0d9eb16f0e624bd8da9737cc66cb
+# SKIP-SINGLE 9f15b4c3ca98e6af3dfe61f70d0043ae896167ac
+# SKIP-SINGLE 9ee6b685a338cd06d4b053e39f3e2da505d20612
+# SKIP-SINGLE 809bd5aa34727151bdf40230e2fbc3151760466b
+# SKIP-SINGLE a2ed435e3aa18c0e6d4997cbb9a81426c952a622
+# SKIP-SINGLE 5c188552341204daf53f0ae2aa4e0c73ec4feb1e
+# SKIP-SINGLE bf91dd23fb7dd37650dfdb218358c8bac659c5a6
+# SKIP-SINGLE 03d2dda12f9e5d877edd15e31d6076361ccbd75a
+# SKIP-SINGLE fb41165adf7c6a354876a26fd7a6cc686f3fe142
+# SKIP-SINGLE fb309c14f0f5075cd649c083abf2a0713b949030
+# SKIP-SINGLE 5eb8d3dba14d94386f42dbb8fcdd28a98d10ac64
+# SKIP-SINGLE d6ae5369b0682ada2e7d801a3cc54f671ed03bf3
+# SKIP-SINGLE 0720354082858f59db9f70ada33efc424126d668
+# SKIP-SINGLE 0f68de830acb5eef41307efc119f3f16fdb35ab3
+# SKIP-SINGLE a18e54f54bdcd5d9b2c11b0307b0a157f52e5926
+# SKIP-SINGLE e0e0b92c1d3fe39085731db04bacd9def31f3940
+# SKIP-SINGLE 515644edc0ed2e73198f4c4eeb822715b2589dc9
+# SKIP-SINGLE 0b9bec6863e138efee77c2948c355b53951e6d18
+# SKIP-SINGLE 283b0db31c87a8bed736a8459ab16ae066ceb024
+# SKIP-SINGLE 10c6303d242ce8f01f38e78da71d01c7a379e651
+# SKIP-SINGLE 96bca89e5b03b6d5ab7ac8bda8216adfc1911205
+# SKIP-SINGLE 475b4768c856c0a25ee236faf0c30b39d5cd804a
+# SKIP-SINGLE 67ac8603eaa5618622d746f4097a0ba6ca2f76b3
+# SKIP-SINGLE 45158ed98b345145eb3e9f8c27b0591433465ff1
+# SKIP-SINGLE cf72d9de0f46960d260e3f5eba843ff01f30eff0
+# SKIP-SINGLE face460c41f59b5097748159ce64a5a09b277dc7
+# SKIP-SINGLE 59f7b155119b5718b83f0bac7409dd597002c89b
+# SKIP-SINGLE 1d3c0d1716eb2025c1dd2e07195b55bb5781fdd3
+# SKIP-SINGLE adac6fa11a95b5c3dd5ae5766b1539687d5931f5
+# SKIP-SINGLE 4847522fd4030af7ddb92b789545bc4e253524ee
+# SKIP-SINGLE 96e2863f2e85bc907e5fc0cb7d86e0b6ff54317a
+# SKIP-SINGLE 8d08a8a1070435e12b77517808df34a8093abc67
+# SKIP-SINGLE 7ba9a4c895b61d5c12118a18cb337f621bea4442
+# SKIP-SINGLE 922c4128034149abb130c6a9a06efa72659ffaf3
+# SKIP-SINGLE e4684a2f9d07ca6ad836028514dda8e3e6643bf8
+# SKIP-SINGLE eab243d22203e0aa56576b00568a93f18e8196cd
+# SKIP-SINGLE 50604ff3872a46baec8578b35db92d9892a35396
+# SKIP-SINGLE 63a1f317d05c8eed256251e7952e621a37b5cf7b
+# SKIP-SINGLE f24c0c7111d9a11921c057eb8d77ca4287294c0d
+# SKIP-SINGLE 689bb582623450826a9e2cdcc2aa63aaa6ab5764
+# SKIP-SINGLE aadb83da748c6befaabab0583fd38bac7fb094ba
+# SKIP-SINGLE 661567b7cd8092e1b41346b77e97201ea4d2efc2
+# SKIP-SINGLE f0e83548ee9d08a558363f73d6ec8e6f30e1cab0
+# SKIP-SINGLE 1a4aa391eea22fc053aa40c1827c7726de5fa7ac
+# SKIP-SINGLE 3b58bac273b517844210c9ecd07757625dc9804d
+# SKIP-SINGLE 26db0a032640a107bb0155b2f1eb7a586dbd8985
+# SKIP-SINGLE c6d819ecb5dafddb7b4dffa4c84f5264a3061d53
+# SKIP-SINGLE a90803a4d1bc47fcfc3b9a3af519cd8441bd92de
+# SKIP-SINGLE ca907fe89b16d59b067669f1c43af3eace1509ea
+# SKIP-SINGLE cae7d6cd58868916bcec34d9572736e7541b9710
+# SKIP-SINGLE 6bbbf3fd829f5000acb63536b5019b5be62d3e66
+# SKIP-SINGLE 01334409d6b03ef101bfd5cc8f5589220fa16483
+# SKIP-SINGLE f69a2b851d80602a158f8878811a63b219eb7fc4
+# SKIP-SINGLE 4a00e47d4d75528ec69291c03615bd669c58ed7e
+# SKIP-SINGLE 4a526ab48d10a26c9f58bde504023dd83017b088
+# SKIP-SINGLE 4cc1374786dcc28b80da546e708f7360f102abd4
+# SKIP-SINGLE f8a454f3efa10d59b8228b5c1373bfc9fb8ed718
+# SKIP-SINGLE 63078fb5af152934c5aa5facc5afd7f8e1907ade
+# SKIP-SINGLE 0cbe9c204e938977fef12dd4cc47d43a702ebfa9
+# SKIP-SINGLE 0ae14c17a24545dacf8ed309b2a75f8f1ed7da5c
+# SKIP-SINGLE 65c0d931f79672e15c6dfd633b619eabfbe9183a
+# SKIP-SINGLE 1f91b8c6eedc12fce03e76ebf8b9c039c5a0a0b4
+# SKIP-SINGLE abac70f198fc6502e3b4d81f9d9590e9d7432378
+# SKIP-SINGLE 9ff098615f92cf9fe4aa0f1c6835dbf9198daa6c
+# SKIP-SINGLE d19bb4861553fe82b86ef09db6cb6b1fe1eae829
+# SKIP-SINGLE b8127e988e2af662bdcd7cf25d281469a5142df6
+# SKIP-SINGLE bf253dd2e9e41a14b813692828ffc43ed24391ae
+# SKIP-SINGLE de1f89c202427a8bcb783f0b44fd02326b320a65
+# SKIP-SINGLE 734eb8f940c197e4b3548e7b79d716203e37aa8d
+# SKIP-SINGLE 8f1670b40fc9a779303207710a913b769170e82a
+# SKIP-SINGLE 9da698575addc4b9c007d7d6c1590bc5ac245bdc
+# SKIP-SINGLE 7d3da0a37edd57f6a31dff4864bcf1753de48698
+# SKIP-SINGLE 5630ebaf74f2f86e5d59fe4cba5ba96333e9fa6f
+# SKIP-SINGLE 9c31066ccdd6dbc7e9bd7a9a56de5c3103841018
+# SKIP-SINGLE bb25117eb40a08824142a5a56acc14d3fb4c89a4
+# SKIP-SINGLE 82a018e0622221910a7a02f683601c9f8c569cb1
+# SKIP-SINGLE d66d6ec5138049b98d99c4dcdd2c78582a6afe0f
+# SKIP-SINGLE d9db77704026ab0871325d431cae765981d167c2
+# SKIP-SINGLE c0ac7d039fb003444769700d60d06538341ba884
+# SKIP-SINGLE 8f3af3f61f43f2090bef30edbb9f8ae1a36c2e5d
+# SKIP-SINGLE bdea0f62b55e986136f5677369f354e4f5849863
+# SKIP-SINGLE 414a2b5bbc6ce441a8102254c593699e503d4f57
+# SKIP-SINGLE 89abc8d66f7668060305e9f0e5dc3ebfddfff3fa
+# SKIP-SINGLE 9b5f8ebb5bb970c34400b149190b2d16886ae814
+# SKIP-SINGLE 59d53e1fde516b911c29cedf338779df29f59dff
+# SKIP-SINGLE 84caa1a404cb89a6f02aa1cb517f5251e7e0e022
+# SKIP-SINGLE 6eb77feeee2d85cca1d6695f809072c357875ba8
+# SKIP-SINGLE eaade31040503efdce5c0daccd4c06f856d3fe2f
+# SKIP-SINGLE d9670ef135893c41d33e5bd12c69659bb5d6158f
+# SKIP-SINGLE e3ed0208a8ce25ed1d6c82e7e5bb3058d074afc5
+# SKIP-SINGLE 86a22004c9bdd1e93aac773cfda1932061f3b724
+# SKIP-SINGLE 6e205873992a2f8eeaecb30adf56346481a2c192
+# SKIP-SINGLE 772357698a226cdbf123d04d58573b79fd8814a2
+# SKIP-SINGLE c8d745d10a45ca3f378d7434f1cff73ae02ba42d
+# SKIP-SINGLE b45122b7132bb4b7e41fff5434e669e4ca671b8c
+# SKIP-SINGLE fcab7f72e1765b883537a0ae2c3a82a802539375
+# SKIP-SINGLE a49be9dba96575b68f0657c21eebcfbb56463021
+# SKIP-SINGLE 4c33696014d28975bce559a333c845fffc695428
+# SKIP-SINGLE 4a0adfec2a1caabca3bf99881f98f24ad12216f9
+# SKIP-SINGLE be1b64bdb515d8328228138982850475d15a0feb
+# SKIP-SINGLE c6be6fd6ccca9b9af1d9c5916d3da39f965e0ec5
+# SKIP-SINGLE 5976919a3325c4512e450b9649a510f05e7d4fcd
+# SKIP-SINGLE 0a014a386200532d92974d255b0b3f6b33d07a22
+# SKIP-SINGLE 82778374fef72583ac7c64f96187f56b1641ddea
+# SKIP-SINGLE 10d7284a2a1e8a543b31e5c99c2fc0c26c8eb681
+# SKIP-SINGLE baf16746960ad5f7baaf21b44feff9c8f3a4fc29
+# SKIP-SINGLE 2fb2862facf3eb70897a2e5ba342971ce696bc5d
+# SKIP-SINGLE bbf8b1df90f327a74423b2ccbfe557da9b04dd9d
+# SKIP-SINGLE d87d9e41f5890fbe7d279053c9c7328890c94b2f
+# SKIP-SINGLE 89172ac4376403b987bad897cdcfd22f9e5d97c8
+# SKIP-SINGLE c31b471cadcb9b8171de04b09a044bb775682a3a
+# SKIP-SINGLE 4088e467b3be3fcf6a1813bc74de7c4d3c193f1f
+# SKIP-SINGLE 8124ddf387451ec95ee4f8e0f726ab234bd8b762
+# SKIP-SINGLE 2cd60cb592930d985565612e0f22766b98fcf341
+# SKIP-SINGLE 403a7e59d5c79d81ee018fd9e648a2af744211c1
+# SKIP-SINGLE a8d358ed231b7656be50b034484b498b0b222445
+# SKIP-SINGLE 9709ff1436d547664e6b3ca252cd37665467b4de
+# SKIP-SINGLE bd3cd579cb43ace253e245a7026b172f216f3a1f
+# SKIP-SINGLE a317620a52746ea4346eabf4559a1caac2b63011
+# SKIP-SINGLE 47b22e55141da090a3d4688851eaa808f9489078
+# SKIP-SINGLE 69cbf2b2f304f82c6d77cd663d4211bf125ebe74
+# SKIP-SINGLE 83a146b24ec230539c4520a4315b8bcdeebdb434
+# SKIP-SINGLE 17ecb1c728edebd00a787fd6c4bdf8b7722e9a2f
+# SKIP-SINGLE aba160b043588171eac8235105d45b30a7f141f5
+# SKIP-SINGLE 05b733e86c108bdacd3ff45d05d560d7b8778a9b
+# SKIP-SINGLE ca28d5fd72d3cc7e960f4f2bd1d8cf00ac3622dd
+# SKIP-SINGLE 6d1c453726cf8a903c6bc555bacf20b7a4ac8651
+# SKIP-SINGLE 747c6a0dc8e53d66c785500d122957f4a17a9325
+# SKIP-SINGLE 351576f913ded76fc2e984c3ad42d47c5c5bc482
+# SKIP-SINGLE 94cae7b2bc02f49f238496ae4c386bcb9cafaeea
+# SKIP-SINGLE bbde29c012868e130388d9975beded563643a7a7
+# SKIP-SINGLE 33ce5fe9da02f0d0f4e0c32b86dde5c5e81c9565
+# SKIP-SINGLE c74f30c8e0f1799ebca7eb144c56506a53290243
+# SKIP-SINGLE d7173579a7e9a0f71ccd02fdc9f694b49aadbd47
+# SKIP-SINGLE 7abf1ca1212d91d0d50d3dd4f6386fac98fd2209
+# SKIP-SINGLE b7d1b2e9462e8d81ec44c41d82d1b840ebc831f0
+# SKIP-SINGLE cb2e6461f3db45df70334016b2a8411605eb847f
+# SKIP-SINGLE 6963deed24b13b448835be0d72d9b943ae2a345f
+# SKIP-SINGLE e4b32e3c572ef0786d2e6215ceeffb21d6046177
+# SKIP-SINGLE deeae4c415166eb144d008f0e904ffa70034c146
+# SKIP-SINGLE 634f71a2238b9e29d6bcab196092edfef19ebaef
+# SKIP-SINGLE e39f5e5c806dc0f7ee0f3520993ba061af7cb040
+# SKIP-SINGLE 03045e2e73eba5578218e09127055ab07a7c398b
+# SKIP-SINGLE c158b52ea421b4ea49adb79c445b712d18ad8273
+# SKIP-SINGLE 89c144b83077aea584e9bbbf04e1d786220aec4c
+# SKIP-SINGLE d6d5062bbae5ee708a0b80ad9b5f400320239fcc
+# SKIP-SINGLE 7edbb163b322072da6666240a698b5dc5fc6aaef
+# SKIP-SINGLE 77e80ae0136d1d79c0ee33b9780445aa6498664d
+# SKIP-SINGLE 6a69e49f01fdd025912e2d4397ebe2f51e3f188d
+# SKIP-SINGLE 59035c17d08f0999ba96c74d1763eedb0347d11e
+# SKIP-SINGLE 24dcbf47d826f46821ed484f93ffb89d306a0b2d
+# SKIP-SINGLE 63ecf01d0b0897b948296eaaffd690290d536b72
+# SKIP-SINGLE b9f37a2a09ac6bcef1a03cc49489f15ff01a74b7
+# SKIP-SINGLE c702e25a7a9e1ba2b75942dcc00402947757786d
+# SKIP-SINGLE 5f1039630dc8bf63f65df5c7882246f267d01295
+# SKIP-SINGLE b32900474fb5e4afdfd0c0015f6b08d58b5e7847
+# SKIP-SINGLE a8517ba3ceb21f3fb5c452226d5ca6a3981ae852
+# SKIP-SINGLE a70e54f6f7a6e711bcc49fce4e117d9c3e9d71a1
+# SKIP-SINGLE a2b9d58b2e2f56679b33995e2d86b0624c0b1905
+# SKIP-SINGLE 5adfe6520b5a3ff2e3bacc603487c4f12e54dfc7
+# SKIP-SINGLE ef6c633b9d5532d8888535a43ec8abc7de0a34f7
+# SKIP-SINGLE 1b9b19ebf911a959948de513afe3f639e23f346a
+# SKIP-SINGLE 4c6272373d4e5a6fbb8668f4980bbafbdc28405e
+# SKIP-SINGLE f74ab3e9ef7a5a63efdb4a7e0bca0c9cc71bf575
+# SKIP-SINGLE 038f46c2526fcc3643a74a6c3e9fda40691f4067
+# SKIP-SINGLE fca675dae325a974c625893fb0ad1aa88abeab8f
+# SKIP-SINGLE 59a428ed6ccd7ee41e847b1d63889845fae7ebd5
+# SKIP-SINGLE 314f9fcf6cb8a6f513022a40ee384ff0e4ca513a
+# SKIP-SINGLE 555450c7b1b1c02126bd9fc86486090fe2b829b5
+# SKIP-SINGLE 06ad74581385cd1930a073b2fda314230b254608
+# SKIP-SINGLE 17259826f263f87d45eb98c8effe0ba7ee774f5d
+# SKIP-SINGLE 4814c6b1184a2b3fe673c5389ce0a8d2c67aec09
+# SKIP-SINGLE ac47ef773e0cf734a3e3e4237aca50704a0a68be
+# SKIP-SINGLE 29fcb6ca1280fc01c652dcecc331b20cd88a5729
+# SKIP-SINGLE 37a794ce21aa52180c3b5037c3825efee91ee7a0
+# SKIP-SINGLE 3d9d7b34511bc3601efa2ab4ad24d62c73b80cc0
+# SKIP-SINGLE 2b51859d447cf2914cb64936f18231363d971b21
+# SKIP-SINGLE 82eb75bd542ddc97b94a21bab25387f34c86f54a
+# SKIP-SINGLE 9913638cc596a018c7d687652a3abb61325dc4f1
+# SKIP-SINGLE ff7093d74b51f094b65314e3567fc96a3a37ffdf
+# SKIP-SINGLE c05d414844f6e1e0af05ef0cbcabe3313f5089d0
+# SKIP-SINGLE 43172dd01fc7344f71f6e1d92fe051942f360355
+# SKIP-SINGLE 5d6e42e013caf236f5f1c7a8bca6d76916bb404a
+# SKIP-SINGLE 7e92976bc7973a4b4be0719b06d3751e57ad80ea
+# SKIP-SINGLE 6d4d9225afcca63f36b318b11be945146007b00e
+# SKIP-SINGLE 2f559c267806f8524d43bc46c5814c69074b0b0a
+# SKIP-SINGLE f23894516ac731bc858158c3e7198db8aa54bfb6
+# SKIP-SINGLE 41f1fd53c830666c1274a602ca48c433da2425d6
+# SKIP-SINGLE 6cd45fbf37bd344c87b83424ecaccc8119c30dad
+# SKIP-SINGLE d88d35ffed6c1073a0695ba1e980cb8ea7f09c3a
+# SKIP-SINGLE 17cf659fdfab02d7c5008d4a4b1df11f93b4764d
+# SKIP-SINGLE 6ac6e5b4752a596436b35419e7ca111b04f35d95
+# SKIP-SINGLE 3f841a942b22c4b6b140654d3d8de535b08b672a
+# SKIP-SINGLE e672990d882ce53167b22969eec6b32e96503573
+# SKIP-SINGLE 211db146a2f475047b38b010ea55c27c08701114
+# SKIP-SINGLE 6df64d170a93970fd57932980fceed6bf1853ccb
+# SKIP-SINGLE 94c542da1ac13fc6052d02fc7b960176c09bbaa8
+# SKIP-SINGLE 895bb4c9112c715a1bfa66d9af0d945f4719db55
+# SKIP-SINGLE b9b5cf4196e7a5368c5e36c0c5e0364b5d3e15b3
+# SKIP-SINGLE 999e625bc94d08eadf92d42d5bb0fd6f6d35c268
+# SKIP-SINGLE bfc298ca31d11c09d49d792a88a9f72415bb4513
+# SKIP-SINGLE 76021e1e06c5c1af05b658310505da333bc0c214
+# SKIP-SINGLE 90425b6d4b314f8f4c26cbf61ec24fdffec4c0f7
+# SKIP-SINGLE a102f471b3973d46d6954bc31c6170ddffd508da
+# SKIP-SINGLE c698ac791b3755c340ff945c137f6732cd4e20e4
+# SKIP-SINGLE a2b1795b96b5ac5981220b1056f6ea222bc193f5
+# SKIP-SINGLE a2257a531d0cd4c1d2bbfe374f490fa956be0330
+# SKIP-SINGLE 3b696d1cdcc79505313b2f087fbf742e503a1998
+# SKIP-SINGLE 4c03c46946d95a7e9079a087b5e0e835f5a5beac
+# SKIP-SINGLE e3163f1d4cec335b5941c9bea267fe161c5ab83d
+# SKIP-SINGLE dc52036074c46d1772557436cda2866b346b4d16
+# SKIP-SINGLE 9413488ab4e8752a2fe88ce9f42ca83ffbe5f1a8
+# SKIP-SINGLE ad5488cad62b04ff1ae28cbbe2a0dcb2af817f27
+# SKIP-SINGLE cf0053a66a8055e05e9842c41f60c2130f4dd642
+# SKIP-SINGLE ed2d884872ab18e38ac7d8ba17e1d3a3446029e8
+# SKIP-SINGLE d34eb7a39f15524dd13681864be14f85d15b4a0b
+# SKIP-SINGLE 620794aa93107115b52f3622c7b6934ebc3fc8ac
+# SKIP-SINGLE 5e06f2fc31a12012d73ef741715a68e47f0c3a09
+# SKIP-SINGLE 8bf2e4e282ff3c0661ebea70e574cce16bdcc356
+# SKIP-SINGLE 5ebc3fc47cfefb9f6726e9308f153c0df6941c12
+# SKIP-SINGLE 79d4b6915c0dc3e27ca18353bf53ceb31a14ded2
+# SKIP-SINGLE 20d42249ce8d7fad1e377621e717b238df3a4b05
+# SKIP-SINGLE 4d7a51eba2c780d10a0b0dac33936c178c677f50
+# SKIP-SINGLE 70a7c65742244403422d7c3e4b79a2046c1cefb7
+# SKIP-SINGLE c8a0b81f8ffe093910dd3ad2852dd47a15587d9e
+# SKIP-SINGLE 6f6362207f7d39b5fb10b2968d238e37848a5a9d
+# SKIP-SINGLE eb6ac423aa21a50d86056fdda4b2bd58278dbef4
+# SKIP-SINGLE 6a65498228c80a6cafc514dee7092b64e9bb84c4
+# SKIP-SINGLE b6540a8ef5b2725812760f5a9a5cdaef591cb5b4
+# SKIP-SINGLE 765e57e2d25d34280b25b925dd8ede4cbfd39020
+# SKIP-SINGLE f5ab0db4b03c497112fdcde3b8b270c3fa14a3c3
+# SKIP-SINGLE 7cd401f63db705acb8ede6624c293843b41e7e20
+# SKIP-SINGLE 941937d295dce322e00a1d77b61041e6bda5cfd8
+# SKIP-SINGLE 52089993aa3231ccdfd0469aeb7c3e7b6b89edad
+# SKIP-SINGLE f4603ab67438ec1a31b35918608dc4db410be9c5
+# SKIP-SINGLE 311c278c5bb26291fbe6d2e28130c43a08dce096
+# SKIP-SINGLE c4d723e865e86a83cf87d4cc42e7dbca799dc4ff
+# SKIP-SINGLE bdcd8dd9fe4a9926a0dbc46ee1180ef53a91bf17
+# SKIP-SINGLE 24fe275711aa0964051f3b95c9bc9b4a3e524826
+# SKIP-SINGLE 281d3a7aadefb673917bc585224c9bf7dae449e6
+# SKIP-SINGLE 291531a7e46edcf52f49e193114e818c111d7af6
+# SKIP-SINGLE fd6c673cfa76b30d3910963982e2c28ca208e827
+# SKIP-SINGLE 15e31a4a1fa359cfabda074903fce79f4982245b
+# SKIP-SINGLE 916a87f0a9748b4c31f20496fff3223553f5226e
+# SKIP-SINGLE d73dd4c12c92db4419df1b96b1562c5c821bf877
+# SKIP-SINGLE ac036532599bdd49ab3bdd36437a06a12224a620
+# SKIP-SINGLE b72d1c5b157214bc8feb4e6364ba624f9feae271
+# SKIP-SINGLE 4ed657604d669b4ba05a9280734c5f006939cdab
+# SKIP-SINGLE 92fc5baf17ccd0999f631d469708523de50ac06e
+# SKIP-SINGLE b30bbf030bacdb0b66c0296d1368db7b4c07558c
+# SKIP-SINGLE 643771818e36a8448744f061184cb3411b13291e
+# SKIP-SINGLE af51e6556daaa4e847209f79ac9dbc1a3ecc8836
+# SKIP-SINGLE 757a95906805b1d7fcbe4b536841a7b53ce0c047
+# SKIP-SINGLE ab69bb63641d12f8a53a262f37908d8234935e13
+# SKIP-SINGLE b6288d1322ec476c156c165496d08e8f782bcb03
+# SKIP-SINGLE 74635dafacb9ebb640a4a69108dabdd897c2498f
+# SKIP-SINGLE 29e17e08b395db8e08e4c91a543750f8021376e8
+# SKIP-SINGLE 0c33a8ff4bd20fcb5f2d4d2a27907c77804f4e42
+# SKIP-SINGLE b6e7df0926b1a569a582b0d3ff0da0c27ad368bd
+# SKIP-SINGLE bb8f8f5cfa0f66729c6c6a333bee5bd4ba16c24c
+# SKIP-SINGLE 7dc99d5d51fcadafcd7e38f169ef8b353db61e81
+# SKIP-SINGLE bdadeff503d1796758a498dee218751520bb0cf8
+# SKIP-SINGLE 128cc4a2f401e96936e9e5791e65fbdc35ace6b2
+# SKIP-SINGLE 3e18100038a0514b1ea6bee01a141f1477fdfbf6
+# SKIP-SINGLE 5992502ca42263855e327239eeb7f51b59a2703d
+# SKIP-SINGLE f63e1740edac418c2ab88d72e1ee56cecfec038a
+# SKIP-SINGLE 5dda07d22c8d974b31e196a802414c267fac5cc9
+# SKIP-SINGLE 9901f47ef77e777ebe0183624024527ce691256d
+# SKIP-SINGLE e65d2f364cf40891d15009e9764143a45c2d164c
+# SKIP-SINGLE b9c228438d34b15ae2804a563d4d52b5e0de62ad
+# SKIP-SINGLE 9273afa89034783aa26d4f5bb43cf22afce57e74
+# SKIP-SINGLE df59970cc41cee834f2432a18a098ec7de16f7ae
+# SKIP-SINGLE a42d67628942244b0cb90276c4e0ec77e967c0bc
+# SKIP-SINGLE 26da67d10b93e2997679e27b56a072e4767102c2
+# SKIP-SINGLE e1757517c33d9c6428ecab8bc277aea14ec0c96f
+# SKIP-SINGLE 7720dceba1079151c37aa0a3117ac22dac45a119
+# SKIP-SINGLE b670b2d8be07dd47274e4e771437b6c4e8649d66
+# SKIP-SINGLE 39e224ba18485d7da68d13579c74afb2cc86f382
+# SKIP-SINGLE a5e428a638718223b0ab667382a8493a135db0ca
+# SKIP-SINGLE b3dc6e8f06892869e0dcf39fd226b63752ce6cf9
+# SKIP-SINGLE f46bfdf3234548f664824b7c96838d3f918950d7
+# SKIP-SINGLE 6465002b8a51d065a662cb589e8e1cf0a78ad160
+# SKIP-SINGLE dba7034ea10fb394b0dcf91256b7df094218119f
+# SKIP-SINGLE 63bcc81d1df8524b20dab1fd45b2cba4d822a786
+# SKIP-SINGLE c77ad1866d0e559db41118ad5a2c306c81fa3c21
+# SKIP-SINGLE 318c4772af4fa04fd8dc498bdc252b691b3cdab5
+# SKIP-SINGLE bebe5a9791f7db3f088e0c07b2fd68e1d21bb161
+# SKIP-SINGLE 79f7d40fa850806450621f2fa4c73974399bd7f9
+# SKIP-SINGLE 1b72dad74f2e193e8da8de58ef8c46341897269a
+# SKIP-SINGLE 8b22849a5cef3e81e8b81cf7f32c186471607e06
+# SKIP-SINGLE 868b6b454ea75361a706ab57b45b6a49b124231d
+# SKIP-SINGLE a2cf65d2030c7856d029e43fec378efe42934400
+# SKIP-SINGLE 976357769fe33e36afb37d5cd663587f46e88d0e
+# SKIP-SINGLE 759a15d446b7f728d2d146cb1bfd6d722df9e998
+# SKIP-SINGLE 7726cb254503c2c3d082ffb8aed9c12cbeeec12e
+# SKIP-SINGLE e25cf441152746a4686ab7adca8d3302e0740189
+# SKIP-SINGLE 6e1e1bdc2c6ee45ac12283f8e8096723d60d93a1
+# SKIP-SINGLE d025ce26f849ae8429f5250eeaf6f4915befe804
+# SKIP-SINGLE 80826b8220c6f26609ce916ceee3a0bd143a1b41
+# SKIP-SINGLE 8da012e224276e42c15d613c0aac3ce3e1a3d939
+# SKIP-SINGLE 13651c52ca6c90265fe568a62db1f81152cfbfa7
+# SKIP-SINGLE 231c71706b3b5eec8038986f54198a8983ae83c0
+# SKIP-SINGLE 45a4510738a0878267fca5fdd687981c70209023
+# SKIP-SINGLE c7341aad72ee4cfca5c989ef982f07fbd14d8837
+# SKIP-SINGLE f78257006c46ac537aba00658b11a75a11bd1fce
+# SKIP-SINGLE a556a2ef5b45a25ff5df9a7cf3dc50e1ec46224b
+# SKIP-SINGLE fb9711df98be83c357321761d06e902e5410da79
+# SKIP-SINGLE 13811eba32c8d43126e3d137ddcedbdab4dd81c6
+# SKIP-SINGLE c87027e054ec247f3c7b80b2159cfcc633bfab7c
+# SKIP-SINGLE 099f9159c4312ad17e51fd3c9571cf525fc01b15
+# SKIP-SINGLE f9723f947a919f70aeb54a9cb6515a4ead3c90d3
+# SKIP-SINGLE 53947aa60b193ec9a34442d4492ddee9ea36ff30
+# SKIP-SINGLE 5aee49d203aeae2dabd1263736c0c6bf799f4f8e
+# SKIP-SINGLE 721d1102986ad16bc71dc7a460ad08cbbe3ae979
+# SKIP-SINGLE 15e4c44564829f2eb3a7845ae94e064540ac1a4c
+# SKIP-SINGLE 8c149505a08ddec931b54e358f4d43e847920861
+# SKIP-SINGLE af7bfaad6a6efa67cab0855b93ebdd920548a007
+# SKIP-SINGLE 988a5133dc86e28e4b097d2c8d64d25e37bb6c5d
+# SKIP-SINGLE 1deb54f5c9c0b4f3c594e4f4aa76b42a67643976
+# SKIP-SINGLE e1d945421522f5b944b35e70cc0a535acc942230
+# SKIP-SINGLE ac297b67bb5fbd4488023ca693a1dc62f012da5d
+# SKIP-SINGLE 210a3c0b3ad2a944bfed4e87a5039a9e4e14329a
+# SKIP-SINGLE a11dc2c8ad5f4162fbad497ce7a813d9f58837b4
+# SKIP-SINGLE 8f446c06498b0c41e58d9265aa72c4615a220956
+# SKIP-SINGLE 79dc3a717e23cf66d04cf3ec3392bd7635839bd0
+# SKIP-SINGLE 187c1eed6f5e21088c5b9b129c65b3e2fe512d1b
+# SKIP-SINGLE d88694315f88baa24d4e0bd40be450218088292b
+# SKIP-SINGLE f3fd0293d9112e5e1ad9ad3bfb1e982dcb0d032b
+# SKIP-SINGLE d6ab30499153b2d6b9565039714f210930a10f65
+# SKIP-SINGLE 592bfe5a978c949883472e66bd6c00f58808a506
+# SKIP-SINGLE b3d858da8d577449e2ab40572422fdd1bdf8b538
+# SKIP-SINGLE 4da353c6a3900ddacab00d685432fba12099dbd0
+# SKIP-SINGLE 1001af9b847c1c338638ba1aee037dd8451882d0
+# SKIP-SINGLE 87bf022f2f5457febf23c2ce792c549928771bbd
+# SKIP-SINGLE 203b6ce9fa148ca05fc2688a8a1a607dc922acd7
+# SKIP-SINGLE edcadf5c440a95c0c6a564d89eb9beac64e229fc
+# SKIP-SINGLE 3ee58c64e57cde232a062cb199688b2686488ef1
+# SKIP-SINGLE 5c406adac75e1b007545991fb7f20068bcaa5b22
+# SKIP-SINGLE 7ce2c17a0fbde3203f311c6b91d8bb2ba77adeda
+# SKIP-SINGLE 65eb55ff4194c67ede020ceabd7b92e7d2128908
+# SKIP-SINGLE 097f36bc75a6570e64f80451ae4bbe2172d610e0
+# SKIP-SINGLE f867699b23ad012ad71f08f88ecf3e0e8df045da
+# SKIP-SINGLE a5803441934b5a128f02169c37e4e00b25b4fc10
+# SKIP-SINGLE 8bfe8ce8d0885e8022b2bea82d1cff9cbed86fb1
+# SKIP-SINGLE 96fc40d7dbdc77efa7b2e01f231bef9e19e96786
+# SKIP-SINGLE efd20b8c4bec0b6edfeb0c415719cb7b230496ba
+# SKIP-SINGLE 34d1a15307a4cb1f667e8af6ecca523369c436c1
+# SKIP-SINGLE 1e9bd1df4c1def12750b2ce6dc335c1921a21686
+# SKIP-SINGLE e642113184136a66fee782c3cdec832ec2ba4c0b
+# SKIP-SINGLE b8aeb2e35d99e14970d15561fcf161ce78fd2426
+# SKIP-SINGLE 16b2a5471eaa7ae2514398720696b3da12514e84
+# SKIP-SINGLE 5cbb6ad8951e8393c3cd728738214a0c87e149be
+# SKIP-SINGLE b3038fa86716edfe9f015c3d0a4c53b9a61c975e
+# SKIP-SINGLE 2b56339f75811a670a18439fedd17de932662c78
+# SKIP-SINGLE c43a9d940a9d033f7770f241f920a537167b211b
+# SKIP-SINGLE 37381fb9b2cc225d127d8eb7cfc0e42c27cc1413
+# SKIP-SINGLE d234e9bc8ae3c8ea1ecb82970a4fd1fd89850249
+# SKIP-SINGLE 70fc2a742d28697b0bb05c16665f038f6f79c86e
+# SKIP-SINGLE 3943db1ab27a29105520bb4e2975e68540e3f055
+# SKIP-SINGLE c6680e15d7c46b9c15358c5bcca4c70b3b2608be
+# SKIP-SINGLE 1121416cfde99f0738d0dac63b6fdd2667de2c5e
+# SKIP-SINGLE 15b4f9d8786d4ecc9eab81d114f09448de2b9ce9
+# SKIP-SINGLE 68472f45a6a441b1436b5949c0384dd57111077c
+# SKIP-SINGLE a80140032be992d170925f274fad215de97d9a50
+# SKIP-SINGLE 7e3d6657e7a952c2eaf9d814ac639613ec81ac1d
+# SKIP-SINGLE 7ad90d410813dae9d2fda3c251d14678b8f104d0
+# SKIP-SINGLE a5524504164ed9077984b90ecf5067d1e8bcbdb2
+# SKIP-SINGLE 2a5c81a5c92d15e8db471d16f3a014a338f9c271
+# SKIP-SINGLE 6ce8092a01519acd2afe29a68b11809280677ad7
+# SKIP-SINGLE 28cd3abbdf24660d8c3587ee983037f82058b87c
+# SKIP-SINGLE 38a5a36a17578a5e06ab18986ce6dae68938e1be
+# SKIP-SINGLE f42b2b0143f5f6e6fd9741b482cd98785feb95da
+# SKIP-SINGLE 17807af213da9eb08507d47dff142a1f8672b4e7
+# SKIP-SINGLE bebd14acc1f646c79702fca4f7081df30a49a66c
+# SKIP-SINGLE 770e52e7001ccdd309a47cbf8b8c9862bfd44ab5
+# SKIP-SINGLE 2b48e5f979610de9c92df24d7cc6c47b6d8d83da
+# SKIP-SINGLE 5a9d4d67043e86831df9c8b3dcb398c45b01bb06
+# SKIP-SINGLE f4d2f75a0782c53bfb09b70bc75de3c974ae5002
+# SKIP-SINGLE b21539f6083bb7be6ce3b7d7701b270bc0bf384b
+# SKIP-SINGLE 1f2529df7d4663597d6ac72ac001def4cd049c1b
+# SKIP-SINGLE 25127da57f5de6ca42c90206f1bb7de0efb41ea0
+# SKIP-SINGLE 54e18532e7e731ec556e4039d677592215a78ac3
+# SKIP-SINGLE 5238cd1e6a9b3c310743fdb4497f8f16d965367e
+# SKIP-SINGLE 01442a9ac9c6e6a652b628cf18b90a7e30bff845
+# SKIP-SINGLE ffa59bb1611609879151b6dfa94772f9e2144849
+# SKIP-SINGLE 6696b561d4d37aebdbb42833d8b5a8d1f4e14482
+# SKIP-SINGLE 530faee2752c7b316fa21f2ac4d1266d3e7a38e6
+# SKIP-SINGLE 53f9bc6908a4da8f5c985e8f204a479c828c432d
+# SKIP-SINGLE c69c185109c90ecc486ab707ed32d7bb7aa467d5
+# SKIP-SINGLE 89cbff32e41771a64ba62e449ec797d55f86f15c
+# SKIP-SINGLE 3c5e3ca2badeda8637e84586eace6ba619f0110a
+# SKIP-SINGLE d5f6dc131b63d6bde096c03927c05a490c707c41
+# SKIP-SINGLE 9d8ce520f03217e5aaf08b3e252a1bb82c3fc641
+# SKIP-SINGLE 05f89e8ef4eb5fbcd04fcc9c0dcb92f90ad6b28c
+# SKIP-SINGLE 79483a5873a90bb28178af59acfdb00040c3d23d
+# SKIP-SINGLE bb0496e7e55a7fca89c51eb0b85dcfa6904ea3ec
+# SKIP-SINGLE 4acc4ac66753ff1556be907f2611b48ffc3fc79c
+# SKIP-SINGLE f7e10297d18b17f55b4a8442a3307db00605d46d
+# SKIP-SINGLE 73ced8c23ec3d5cdfa6d926af649235104707d85
+# SKIP-SINGLE 8cc8adb04d2861fb1b1bbb38e53feccf3a2fc1c5
+# SKIP-SINGLE f8b07ff4f318d799a471c9363903e3929fd5c844
+# SKIP-SINGLE eb1d22b136a3f7a49b4060553b79ee188f55a498
+# SKIP-SINGLE 6487d4ac5da92aab4d54b5702bba24a5a1ce8432
+# SKIP-SINGLE 1f3ba658fccdb0b35bdbbdfeb8591dba72ee983f
+# SKIP-SINGLE 43b6f05dfb46637a414520b27430fbe3b0f005fa
+# SKIP-SINGLE 65cc8efa333bbb66acd7b19f4b39c3138995e864
+# SKIP-SINGLE d432cbeb27c1f0a2e59c6853b61ecba3615f645e
+# SKIP-SINGLE 886ded1b70f24c52ee526f0c4a69ca06829fb2a3
+# SKIP-SINGLE c5ed3a72a8a70931ef9b0f9d69f73ff0fd40cadb
+# SKIP-SINGLE 208a11d3f0ede17b29da45c2491b703b6942a764
+# SKIP-SINGLE 1b809f378f6263bc099da45c5e4a42c89fef8d71
+# SKIP-SINGLE 5c890bfc191d0cf18dccbbf50ebdcde946a0d7fb
+# SKIP-SINGLE b16d553ecd1b0478ba28dca5d898fd22aa130fd8
+# SKIP-SINGLE 3568c5d86fc8d37d761245c19246f76803fb1f16
+# SKIP-SINGLE 1e09364d677b0fb57efd18369c55e8c2d0e826f5
+# SKIP-SINGLE de1b33f5a8c6ceee9be59285f70370c3cb2efd34
+# SKIP-SINGLE caf155c4638d4704b2a099657153c9abc115720b
+# SKIP-SINGLE 79e133da034cd2d7cccfc5a6eb7db340f2dc45a8
+# SKIP-SINGLE 7be160d80002cd000f33da38d3a2f7a2920c1bf5
+# SKIP-SINGLE f6d6ccc984ac241e1a5f61d770bf77c15f30ad07
+# SKIP-SINGLE b23daca20788ab6b54362c5bdb0470887de106fb
+# SKIP-SINGLE 0fc8671d10ccab52d78afdaeb715bcc9e52c0ac0
+# SKIP-SINGLE ba0a61d10a5aedaf4b7bb61aa3626f385d6aba12
+# SKIP-SINGLE c6f42387e32a4e99cd9ddd203ab51f3c5694054e
+# SKIP-SINGLE 46e7613ad3b88807d25cfab3d78bf46c9e2fe13e
+# SKIP-SINGLE 843b55f6822bc1e8b97b91222e7bc03b5caa9919
+# SKIP-SINGLE ed943db794987cb6fc87b55d68d6164190ba9a24
+# SKIP-SINGLE b799cc271d69fc494da1fe04ca8ec6c529a19a19
+# SKIP-SINGLE 289d6b2265e19822ed5ad44e5c62e9bf3750f606
+# SKIP-SINGLE b42df36757e7c86f33730090a8a0789e957f8fba
+# SKIP-SINGLE 527b8a807143253ed8e52de004fb3cc9a17123c0
+# SKIP-SINGLE 2e669305fca1d20e9224dfe0146cef8267c47071
+# SKIP-SINGLE 99f8a1c91733a8aaa47818e78dfe86c5635ce086
+# SKIP-SINGLE a8e3b29b2b73292c8497fee8932b04fa07a2c08a
+# SKIP-SINGLE 8264e8deaf6d67492964b63bb729ab6fcc350781
+# SKIP-SINGLE 50dd037338784381300f411c64d39a9fbaaa7f5a
+# SKIP-SINGLE a2323c7ccb0eab1b6395d5d1d7e18db617354e13
+# SKIP-SINGLE 91d539b0772d4b2a6bdc3fbccf92dc1fcc7f747a
+# SKIP-SINGLE 4ea90a711d11b14be728241a4454f8c5ee7b6478
+# SKIP-SINGLE c3b53559965a4c6f48274c3cbcb43eb6ef23ae14
+# SKIP-SINGLE 97267d2bf1fbb9279d32f75eda9dbcf0c4316edd
+# SKIP-SINGLE e704a6956d86ae394ecb029e066bf8d8c061baf3
+# SKIP-SINGLE 809934f0220e1d9a1780ab97d04fececf2b934eb
+# SKIP-SINGLE 31ec1a7d329cc9374b16c5831d30248c99e93dfb
+# SKIP-SINGLE d93bca019713e98228aca9f4d1a4838a72b1cf92
+# SKIP-SINGLE d168110a322389a9f991d7a5bdd1cf777642c990
+# SKIP-SINGLE fe7263803c37c836b3484861fbe13674a5063b4e
+# SKIP-SINGLE 29c7f8c915c3889dfd5b25878aa0692f826cd38f
+# SKIP-SINGLE 6e73e07a6f5cbdd1c5ae6e0f3fbd0f8f56813f1a
+# SKIP-SINGLE 3b9dad88e02f05773c599808266febf3e4128222
+# SKIP-SINGLE fddd63f8b854f6bfa91403f69ba694ccb54197bc
+# SKIP-SINGLE 97eec9db79443f99eecfd84af73e5249748b9796
+# SKIP-SINGLE 11e22452b0ab6f2ea7679665ed8e9abcbc03eae9
+# SKIP-SINGLE 79d585c2befb81ac5480a9577eaeb6e8915cae23
+# SKIP-SINGLE 59698d924e541b1768a61caafd0dfa40b5ed4b34
+# SKIP-SINGLE 77e194971c5370856a63cf02397d79f85d6b342b
+# SKIP-SINGLE abd8c9b4d71651b00552d3d5dea119f22adf3874
+# SKIP-SINGLE 69caa111c290eb1f02013c407f4ac2549b172c36
+# SKIP-SINGLE 8933cf86a1c64fc3302188629356084bcbfc65dc
+# SKIP-SINGLE 6e90768143ff47e96a70d91534344161a1d85f46
+# SKIP-SINGLE ffdb91c6b344b6b341e75ae981ebdb3e66b94130
+# SKIP-SINGLE 2601aa9105d935441ed25370feeeae3e717cc791
+# SKIP-SINGLE 8d5dfafab7dc40d4b74dc0b56d1b314fd8cac390
+# SKIP-SINGLE 4467073c50d2c7fbbb30530d1a0a25f8272ff56f
+# SKIP-SINGLE 4459dcc07865f6ae1f21f624fcb09cf8fdaecdb5
+# SKIP-SINGLE 21e475ea0c0d04ae7634f377ed64fe179388b133
+# SKIP-SINGLE c0d24d5316626a3d5e76f99a0f418463cb355459
+# SKIP-SINGLE df06cfe4a9859a00d7ea046be8f82f1b9e4564ec
+# SKIP-SINGLE 1ae8a18d949e3a3dc3f7a6f2284ecb35871416ca
+# SKIP-SINGLE 6e974130d709e9e8624dab5c24a6639c0331cb77
+# SKIP-SINGLE ca194ae5c9d63c032827af6c58132b066bce7fbd
+# SKIP-SINGLE 6927f237679e73343aea0d70e356fc247c05c4d6
+# SKIP-SINGLE 673d281b82886490707f3356a87b5a992d1dc0ed
+# SKIP-SINGLE a902af6c1b04abcac4d6d221a2b0086cc076bda1
+# SKIP-SINGLE e2613f41213c89bfd90d34a7a5fb120e7366ec6d
+# SKIP-SINGLE 3a964dc5c124d1b5402e7e5cf7a6b6f28310e67b
+# SKIP-SINGLE ac4dd5f244032148595fb787ff926882390b36b9
+# SKIP-SINGLE 952550258dcf06bc03662974aa6b6db9d792aedb
+# SKIP-SINGLE 667e002e91a26c20089c5843254a39b771b64ab7
+# SKIP-SINGLE efd80237ca6085f28497bded259a92a48bb6005e
+# SKIP-SINGLE 22910e71e5092250b2134dae07bd8e2a82e4f750
+# SKIP-SINGLE b9683230ecaada87f23bdba59ef044c4b0374216
+# SKIP-SINGLE da383aeb8e629f642b46e9c64b2ffcec9976c23f
+# SKIP-SINGLE 0689a4ac508a213f29c11ed6230596885d42f89b
+# SKIP-SINGLE 1fdbeffe3a65cb23abb43a4ea59df9553c9246f9
+# SKIP-SINGLE 40842f67afb2931de6789237a49570f99b70404f
+# SKIP-SINGLE 4e1f92feb3a861f93b7a285715d03be930b41b91
+# SKIP-SINGLE a0f060939456f3680823e34f430e482fcde2f5dd
+# SKIP-SINGLE 5dd2d50f3d5e65b85c87da86e2e8a6d087fe5767
+# SKIP-SINGLE 0776ac06803100e36d2ff7532744186f70bfcb56
+# SKIP-SINGLE e490ffcf953cd2a82aef86e05da24352db5d4568
+# SKIP-SINGLE 58de11fe1339a1248f9b0bccb3a3601a9d8f56c6
+# SKIP-SINGLE 515eb6989575dc1d8e8f996ec65494e637f24ffe
+# SKIP-SINGLE 9034dd053163d6fc383d1ea4223c0b4dd7e9fb39
+# SKIP-SINGLE 13824c44d28427931a7e3284adec9a3a38cd2323
+# SKIP-SINGLE 681faf9f0bc41972932b72ef34c026419b6eb54d
+# SKIP-SINGLE 63cbb54d7e163f74657dba46829262282ccda0df
+# SKIP-SINGLE 3478e64c88fe0187f49343ed778d7e9231cf5837
+# SKIP-SINGLE d1aacceae939318f419e0c265358e041c53f1eea
+# SKIP-SINGLE 164aac0a9919fb34896ddd824394a65802343a50
+# SKIP-SINGLE bf9ec3d91a79414deac039f7bf83352a9b0a9a85
+# SKIP-SINGLE dc94ca7b2b878c9a88be72fea118bf6557259ffd
+# SKIP-SINGLE 9fc1fdcbf330b0a85cd019bb75afcb8d36243524
+# SKIP-SINGLE 758753431af51f7ac79a55d426b915443e66a077
+# SKIP-SINGLE 49c748e336ee3c50e28d2aeda6396efc358d961b
+# SKIP-SINGLE 6fecf6ef2552a9b44c4311b7d5af3af0a5a54dbe
+# SKIP-SINGLE 71857d410635743d437ce1ee73dff69de50030d6
+# SKIP-SINGLE d4a6e42e92ee215659d09b0456032714aab73ca5
+# SKIP-SINGLE ceb9da3b7125fbdf0da04a3b158ac1e792c87f4f
+# SKIP-SINGLE 252d06dd5d177ad3d6d0464eb3e65dd6ce4cce79
+# SKIP-SINGLE 155dba943263236ba2c41926bae3cc45229b15bc
+# SKIP-SINGLE a602d548dfaa1dcd44c3af017ccbbcd3586ca023
+# SKIP-SINGLE dd3f6b13f673433e590c55b24232cf0a7e70de6e
+# SKIP-SINGLE c1e45419c7ad9679771718e91205502d30da6f2d
+# SKIP-SINGLE ec0527d8e9a7f12898c8fe9fdb6daec21c1d2ba8
+# SKIP-SINGLE b2164df86ba80cf4b7f3499596fbcf803395b6e7
+# SKIP-SINGLE 3d49ad73e5a93625629c96b6c0b921bb019ea9da
+# SKIP-SINGLE 89068554d7d0e9970a7269a0963e7a2bd0b1cc99
+# SKIP-SINGLE 483df14d5c4e04ff2a9fec18b68399c0ab2b56b4
+# SKIP-SINGLE 0934363c96ff774ce242b51529688bbfbb48ba02
+# SKIP-SINGLE 159dbd5eb211e36d98e200781f2eae93f0973aeb
+# SKIP-SINGLE 56254fb98c3369392dc2bd4383b7ff2ea24f2dc4
+# SKIP-SINGLE 4633e02726fbd683332eb64dee97b109aef4361f
+# SKIP-SINGLE 79eb840753edb2dd9e0bf1d4befb8e3e1275e009
+# SKIP-SINGLE aec08e609e6c672c6e85d91b84f45e38019ccc9e
+# SKIP-SINGLE 7d9d3951c6736d5606828e2727a7319856511ddb
+# SKIP-SINGLE e793a73fbea3167368bd173211c1995e07dcf913
+# SKIP-SINGLE 404023299429a2619c6e4bc5da80eb248d060ef9
+# SKIP-SINGLE 59ff342869062caba72af7834c00b36753fa7461
+# SKIP-SINGLE e4300777e8cc7559ea29faaeab6cafd3f7ebf3b7
+# SKIP-SINGLE e40f5a91eed69b5d6131671ba1699ce3ccb92f16
+# SKIP-SINGLE aa6cacd7138519aa8906c850950020d0546ae355
+# SKIP-SINGLE 2e595b3e8b887068e47e64116d5a910c1045a229
+# SKIP-SINGLE 91e7df281ee628eb56e7d016093a751f4e04366f
+# SKIP-SINGLE 0aa9f478e962e3e2d146871fa37267709404c52e
+# SKIP-SINGLE 2671ea0de8e90e20241fe0441f4f8b79eeccdb12
+# SKIP-SINGLE 958d6b4cf77af951d1ad40c02c5d5dcc28f31120
+# SKIP-SINGLE e36d3fc452735d1a1a2293e18b8e4ef944f8793d
+# SKIP-SINGLE c094b8c20a79c731cd36e86a3a6bc777606586bc
+# SKIP-SINGLE ae9bfaa891c4f3cacb118aef6e35432d5fbeb88d
+# SKIP-SINGLE 9d14e410dac11990cf0e95a1a77e83827323530d
+# SKIP-SINGLE 148b136651413d8eca0f805c786fb04b9c5878b8
+# SKIP-SINGLE 3c972723e44c9428ea990562033acfbd84ed29d9
+# SKIP-SINGLE 194c299470e087aeeff5c496c7dfc6400e1185a7
+# SKIP-SINGLE 8f5d2a3181d22f858ede3fb6a1452f99272901fe
+# SKIP-SINGLE d50e0bdbac8e6683c6af4efa172c1b801d250486
+# SKIP-SINGLE 1e8074f5ea9e61a6fba33ab2af0c79b9af7d7a24
+# SKIP-SINGLE 9e79575486fb6aeb0deb23e17cb2ce9ec02b5fd7
+# SKIP-SINGLE 3be2a6b8b4098e5cf118d196e4cba37054d8292b
+# SKIP-SINGLE 0fd79ee039de664bc06b0dbcaee786f88a2b079c
+# SKIP-SINGLE de477ec683482a5dd27d791d7fdcfc4021ed3cb7
+# SKIP-SINGLE 8df7f89af672f0592b6a31be9d1687b1369692f6
+# SKIP-SINGLE 19206fd1e764cfe89234ae9245bafa88ef1ec354
+# SKIP-SINGLE 92ffe44834b8f77ee3f4d37edfdb19f30a376869
+# SKIP-SINGLE 5e5cde55e5be6e2d388252c3ccb0d019aee6b89e
+# SKIP-SINGLE f6339412eebdc027b00263ae2b5c38a029e2f7b4
+# SKIP-SINGLE 32d12840e666d1d07c92cc31f0b12965451f7726
+# SKIP-SINGLE 895215854db66ee8017e5ad5c3215eb089d33e07
+# SKIP-SINGLE 469fe6a040d6df612c00ea169670c6d8d7e58563
+# SKIP-SINGLE 9e131f55d8d5a1eeb44e7c5a3a5e56804be60dba
+# SKIP-SINGLE 73d6b19024db10b65ba368bd079223157d73e737
+# SKIP-SINGLE f25ad39983cc3e89b007390bc0fd860f48379497
+# SKIP-SINGLE e0ca8f791c2e4396f1e40d86c136ae547b40185d
+# SKIP-SINGLE fc520f8b7090fb95e61a498b5b23be6041475bd3
+# SKIP-SINGLE cea0d61a69ef443924fdd4e4c429d7103b4acb9a
+# SKIP-SINGLE dd0727e1ec1f535b9b06be88173b4d3ccd55abcb
+# SKIP-SINGLE 3e6c69de9d1ae99ebb71eb2ed04bdb9ee42cbb80
+# SKIP-SINGLE 34e3ad5ae449f4801af09d1df89d57350d0dc579
+# SKIP-SINGLE e726a00381e0f2d8dbfa52a10c82116a8352adf0
+# SKIP-SINGLE 32b9b22f66b1afcc614d5f76860d56d5630c5bc4
+# SKIP-SINGLE 0b43e7a49327ce32c67648eb898551002f135ef5
+# SKIP-SINGLE 81b589518c2e574b084907c7d7fb8e6e5049800b
+# SKIP-SINGLE ed77d1a8c0f005d4f158b635d39db0d5d79fe1ee
+# SKIP-SINGLE bc60ce7ffdf39fc3288938337e7f6c0706b37082
+# SKIP-SINGLE 35dbc79cc3233129da90ae2f4916d73e189b63cc
+# SKIP-SINGLE 41b1d223c6ab7bca1b626a4c07a4f2dda2855feb
+# SKIP-SINGLE bf79dad3f20345ddf095325ce22c0f2a3408d3ba
+# SKIP-SINGLE c4dab6c179a78ae17d02becf66a098bd72a12233
+# SKIP-SINGLE 4c7faf33776c6566fdb374ae2b54960fc70c3228
+# SKIP-SINGLE c469efbd8361cffff72fb6a4aeaeea40c5adf110
+# SKIP-SINGLE 9ea5a915bd1b9458af1587d63170888346e8baec
+# SKIP-SINGLE a516ab79c300517d5c3ab68c45ff9c90bda6c67a
+# SKIP-SINGLE d45e72fe5a9205b2e146d27e8e26233ee8518331
+# SKIP-SINGLE aa6a05c146e94c0afc35b5354d68da55aecb2db7
+# SKIP-SINGLE e2494bdaeea309c6b270dc09beba34da5f193573
+# SKIP-SINGLE dfc7338828a8db6cf177633f942efcb0d7930aaa
+# SKIP-SINGLE 6927841ecba6494858cc3af7c0500e6cd3c4923a
+# SKIP-SINGLE 105c7562dc38de31cda6dfed00a1c260a6e72ea2
+# SKIP-SINGLE 4844aaac199de9af8da0a62b5ae92b1f5a7abb2c
+# SKIP-SINGLE 7fa11be2fae2b9fa5981e01da05cb618859d77ca
+# SKIP-SINGLE 2f6b519eaeb3be4ee6a912b40a21686be12d4d88
+# SKIP-SINGLE 3f98188b864fb4f16a7c2878a96c880ec55452dd
+# SKIP-SINGLE 7ca865dc52a31374c68dc870246353db5acc023c
+# SKIP-SINGLE 5db380abad0482ae74aa71761f0da2b2351ce97a
+# SKIP-SINGLE d353c08d2bf25ea8e42ae4664c3a276d549937b5
+# SKIP-SINGLE 20ab7e07afef7a878565bac97f63bafe5f9d6e04
+# SKIP-SINGLE 35075267a67b6474416e0e413d0d60c1f5f5fc36
+# SKIP-SINGLE d633db5189f335873a03544f9f41dcaf77c8e31d
+# SKIP-SINGLE 88e1f8b02086aaf652e3058b36b7612c073c04b3
+# SKIP-SINGLE c8ea3f09e09b18b909f5a6c5434185b8dbf2fa63
+# SKIP-SINGLE ecdda194a82c8c52bdb948160f55ebbabe733d79
+# SKIP-SINGLE 4765487d5d24fc8a2a06c329dc9cc3bed9803391
+# SKIP-SINGLE d5499e3eb2765ddf212e3f21fed7b356b8f0ec76
+# SKIP-SINGLE c274bd5c52fd64c888b1c713060da881bf72caa7
+# SKIP-SINGLE d96db7b2e8c35ec2970d12c96e2328b684626f24
+# SKIP-SINGLE 935cc42795686710f82b8928b6802f20be8f27c0
+# SKIP-SINGLE 52d5771e0a803f57b8cdd7675bf15f2f9b946039
+# SKIP-SINGLE 9e1186a73279f9e6416cc594171482be5a223820
+# SKIP-SINGLE 905fabe5904c9588bf0c5d0ae15ca0ed354b3656
+# SKIP-SINGLE ba0264e19153281bcf264e99c01c130c701151e2
+# SKIP-SINGLE c1fa5bd8ee3c7f37a9b9304eab6b522cf8718472
+# SKIP-SINGLE 4290f64dc9948264b5d9bdad2330ee15aafe6589
+# SKIP-SINGLE 5a10e6377c2b97420e5617f114bb374d67ec1a58
+# SKIP-SINGLE 2a2b3f583430df8495b566a1dfb1f41c4d61292f
+# SKIP-SINGLE 58398dea254dcfdab58d5439061a513b48cfe895
+# SKIP-SINGLE 5acf75cec1c2cef383a7c022171f5a1d195c09ca
+# SKIP-SINGLE aab5d7b3f3bb6fb82924aaabdfdd6e2a79ad3141
+# SKIP-SINGLE b3023de5431fc308e2a6db61ed4fdd18db785324
+# SKIP-SINGLE 02ae85e8aa735b0d9a312f811d03204bf8fdbd51
+# SKIP-SINGLE d1f315751d960f003317713a65cc480b3d0ee726
+# SKIP-SINGLE 760107639be7657c4a209c9c04b17c79fc19f2c6
+# SKIP-SINGLE 8b7aaf3e56c63cae7e2affc249179e5022451595
+# SKIP-SINGLE 56fb536e78f3e3019b85995ba1d788065c3ac415
+# SKIP-SINGLE 02ef00d89c64d713f29f4ed12dbcae9f8d31bb9a
+# SKIP-SINGLE 6dc4e3b95ca9589f24530979cdc83ea346d1ca45
+# SKIP-SINGLE ec464789dfc5179c72e6929ea99a72f508c562b6
+# SKIP-SINGLE 5ed566cae08d4f39920bea81fd6bf2160f38348f
+# SKIP-SINGLE be0cf9e2995df4d0ff504561afdefba00b49438f
+# SKIP-SINGLE 8c153047e78e078b2001be9cf16ef3bbaa375a39
+# SKIP-SINGLE f14f6180b78656eec2f4dad5b79eb5da20bd0b70
+# SKIP-SINGLE 3f746d44decf9f991ee2a0a0529a2bba9ad12988
+# SKIP-SINGLE a0524584e93a66278dcf7bb998398f7484f9e8b5
+# SKIP-SINGLE b2a5bf142fb25094ff623dc93d2ce916aee3d971
+# SKIP-SINGLE 2f68673a712508f70de20f485422c7e01b8ab21b
+# SKIP-SINGLE 45694a25948146e860738cb4e01de7e7e9aa91b0
+# SKIP-SINGLE 91bc24c46768aab4a851c87edaea05c7476ff779
+# SKIP-SINGLE d2e0d1452b976a51579cf044257326850804c562
+# SKIP-SINGLE 3294ad44ebcd024b4ada68d00bedca33acc52de6
+# SKIP-SINGLE 3933ece030150908c9189c11cf683bb3df9e4e18
+# SKIP-SINGLE 7fa37d7a1439bf8cd76b336ea95d3a1982b3ae03
+# SKIP-SINGLE b257a7894b6b8536ee16e6b334207c8f5c887280
+# SKIP-SINGLE cdbb02a597298b7812b456fca3d61e223dc40b7c
+# SKIP-SINGLE 41c09d347feb94b9070a9aa2c78ccf65be7fd268
+# SKIP-SINGLE c7f141d67829ccef64a5e4e961f098f09774afe2
+# SKIP-SINGLE de0b7af169345442852622bb337483398c583a9e
+# SKIP-SINGLE 6fbea946bfd0119cf517211d058ea277c9209a87
+# SKIP-SINGLE cd479aa8bd498da4d7980a7fe7a37e238761482f
+# SKIP-SINGLE 36af7004e2bf0db1d9c2fd1312215a931c1db3df
+# SKIP-SINGLE 3fd58ad37e12845fab905c00e87ae1d49755504a
+# SKIP-SINGLE 58965d91e7fb5a26a5422357f44d6e841f67db74
+# SKIP-SINGLE c50718dcfa54293b695f8a3fa5cd4d77848ee084
+# SKIP-SINGLE 5276519255c27e7dd01cbc3fea00d1c29f44d514
+# SKIP-SINGLE d9bd334ef367f3e16967ae2ed714ff419f2b5328
+# SKIP-SINGLE 3d6af11c42453065d5ace1223fe99228b7927318
+# SKIP-SINGLE b7f227ed8bece1a8fafd36ce5f0ee0d5913b6f8b
+# SKIP-SINGLE ee93a06b8b1922b31e12cfe60566779f185ddeba
+# SKIP-SINGLE db03eda6369a9d4af3c72a8ab6ec29e3cc58acc4
+# SKIP-SINGLE cdaa3b51f1500ca1d91452037efe68fa0f7808bc
+# SKIP-SINGLE c6029ed34ea83c7c0adbd723d63bd78ff0ec0796
+# SKIP-SINGLE 77882158b2aeff7f235c409d6572173ae4c3a38f
+# SKIP-SINGLE 67a218d33926931b20096edce3eaba2958283bde
+# SKIP-SINGLE d3c4833d1350e26a2ae35e00eaf2d6bef1724679
+# SKIP-SINGLE 2bab0f2db6fff3a99d3bc498d6139ee42aab96ea
+# SKIP-SINGLE 4313c695cd6370667ccf086cef0d9201fdf796ca
+# SKIP-SINGLE a25cd7f68aa5babb7cc9002d89ff02077937927b
+# SKIP-SINGLE cd41ce8c6c107901a499bf55dd2b0383befd37af
+# SKIP-SINGLE 280b8c96ccaeb95548adda78466ef2b1c3cf4546
+# SKIP-SINGLE 57a978fd74454392a041ac65a5abba8d012b88cc
+# SKIP-SINGLE fc53961c1df8bee07b6a1d461d31f449b66f1d65
+# SKIP-SINGLE 350e97d78e7803650c6dd2bf46fcfece8e2b4b32
+# SKIP-SINGLE 304e2a3a05feee6578aadfa0228dde734fe850cf
+# SKIP-SINGLE 874e2525035d45efa6fa374a2ebec3740ecc1457
+# SKIP-SINGLE e2df22fa016247dccc632b2cb4fc5b8ffb4c3c7c
+# SKIP-SINGLE 0069085be2d0e6c7d439372b06b866df4c669891
+# SKIP-SINGLE 72278f21e0ef0c79f756bca08577297d11e22518
+# SKIP-SINGLE 616da8fa8efa9023f56fa731072d877e2150afbc
+# SKIP-SINGLE 51f8e86374a57efe5b8e5c31d96078e63c023da4
+# SKIP-SINGLE a29a3ad55d650af6230e2cfe8ef1ef45b5feb133
+# SKIP-SINGLE 7a9f8ed6fba0d6728cbf185696bdc1a95b1acfea
+# SKIP-SINGLE 7f298bab5234073b1565a7008f63b89979a925d4
+# SKIP-SINGLE ad1baff0a12cb22c5c515e0ba3ed29d4b876451b
+# SKIP-SINGLE fe82c0743b3feecb9b80549ef4bb3dc8529891a8
+# SKIP-SINGLE 89c589bae47fa7faa7273a9df0f4be836e9da29b
+# SKIP-SINGLE 6d8638e5e494fb0ceafffe19bbf349fff643e12d
+# SKIP-SINGLE e89532c7c7c5098a77f3ec6fb5def98b1f9034a2
+# SKIP-SINGLE 15a9e73a1793a61b87d3f460e2e4bc5b7df1e6a8
+# SKIP-SINGLE 4e091c8ddf6bf421a4dd0210a3a4b77a3ecf24f5
+# SKIP-SINGLE e2b774e64a903e856356971c0fc3a3835d3883c1
+# SKIP-SINGLE 82b602dc2f52775a4082d24d64380867da051350
+# SKIP-SINGLE 8ae173a8373c12f17acc9d7b22910cd106c12b4b
+# SKIP-SINGLE cfb295f1e55e4d04beaad5d57ede494c436cf277
+# SKIP-SINGLE 9a9634dc725278a6a676fa4590f53543cada34b2
+# SKIP-SINGLE fdbe3362c5a72be7d4c930a614fe5853bf6eff1f
+# SKIP-SINGLE 72c7ee2e525d87b58a28aea8af8cef31f607d7c0
+# SKIP-SINGLE 85f1ad0c798b5556c37185f4930929d5aa386a5e
+# SKIP-SINGLE e1553142fefaf39d4742d1a161de2bce691204b2
+# SKIP-SINGLE 39aa623479128b465b01490845f0781c03eece8d
+# SKIP-SINGLE 286e308561d00a31e0321919ef36d9bc6dadbeb3
+# SKIP-SINGLE 8af91dee9a9031ac0d49848b16bd288685f1f370
+# SKIP-SINGLE 8783700b23e70874c4996908bf02c010ae6f3fe1
+# SKIP-SINGLE 344b48f490416cb1200e19b28d356e7fb5b04387
+# SKIP-SINGLE 409327ff68f9ccdc8099f6a2ba2fee76abaaab70
+# SKIP-SINGLE f25f4699d760c5409a1571dcfdf4ed0fdac9e0ec
+# SKIP-SINGLE 5cceb6d6acf6299f1347133aec7097b8771ff952
+# SKIP-SINGLE f5f296b0800de4cd459e41b4a7b1cb97673e8dbb
+# SKIP-SINGLE 9aef9e2cb6b547f62911d06e90081af32134de66
+# SKIP-SINGLE 43e9c8e9d28dcb659a43e58778e2745d1279051f
+# SKIP-SINGLE fbf2bfba0770b7f575d8ef06ca3a08cf1a38cc2d
+# SKIP-SINGLE 7ca456da7f72feeeec571ece3c373e2b3a3d327b
+# SKIP-SINGLE 0e7361a5ccce084613d54d6ba3954ffca6074817
+# SKIP-SINGLE 2a9797b422fe8a28bfaab49974ea2be21ae2502e
+# SKIP-SINGLE 5d73bc5c69f56ce1b22c950d19ef6406b662949f
+# SKIP-SINGLE 16986a9cc42ef4de580456f4acc5feba682ac8b1
+# SKIP-SINGLE 2d2cdb4741a3c1e42c8ed771303a878fd428911b
+# SKIP-SINGLE 4725c123f33eb9579b695748fa9f85c9af3eb01a
+# SKIP-SINGLE 0c7024d0d9172322052de2ee571ba64afff905f0
+# SKIP-SINGLE 20d44771201ef96fcfd6aebffe05aa50c5fa8074
+# SKIP-SINGLE 7a551e92005dc9964c1a74a2896b5dbf0ca231b9
+# SKIP-SINGLE c681f374788235cbaf1dca062450202e90fd2a86
+# SKIP-SINGLE b92a5174939fba17ffb5235dd926c7063c13b1d1
+# SKIP-SINGLE 6cabef8799eb053c593f0a5241503ccbfb616c8a
+# SKIP-SINGLE 3e5856b21a83a52dda8c0b3ab541d106d809d625
+# SKIP-SINGLE 86581698acc1a0991592e018c1ba749f3ded21be
+# SKIP-SINGLE baa39e48495e100af6704af9287b544e612c245a
+# SKIP-SINGLE 9c67e8e56d40926454e00b5652c2b519ae0b507b
+# SKIP-SINGLE e961a31507e6fba86a5d45fec7fa616e80028882
+# SKIP-SINGLE 65456668ab1048fe8d77dc76a9e4d84481c218a5
+# SKIP-SINGLE c96157c8f8290bc2049dc947b6d264564659a545
+# SKIP-SINGLE a7ed5071b70f07da4c99198126c48cc6b448090a
+# SKIP-SINGLE 1e624452004e17bec2070b0c0b9f5639f66df1f8
+# SKIP-SINGLE 3f25b22cadc9f73583e83b00f828ee00efa8764e
+# SKIP-SINGLE 938e68bb280c96eaf163bd932ab2582fbe27e780
+# SKIP-SINGLE 3069849bd4c1048a8f8c0467d26560fad939e791
+# SKIP-SINGLE d45253996670509e668d266d577f48deb9c7018f
+# SKIP-SINGLE 43f25120c9a2578df3df47491ed68a0566ff6f61
+# SKIP-SINGLE 9d266f2a6c0e51f184d55c8bba4551abdeca02bc
+# SKIP-SINGLE 76eb88df0243dd15492e71f068fd476be8efc800
+# SKIP-SINGLE 32870d2f207536bb7932beeb2e0ec9a4e0146560
+# SKIP-SINGLE 625ea08652053617034bf8ceee0d6cfae34f2dcc
+# SKIP-SINGLE 657947dc7cf01a13a4fa260691a6fa0147107950
+# SKIP-SINGLE 4fa13b2d838e11cbe3b713f3172721cb61d499f3
+# SKIP-SINGLE f17ca55a0a3c9de1061285763cbf0bd3754f6718
+# SKIP-SINGLE 4c5f1737c4815bd6d167108343a61da9a3882f32
+# SKIP-SINGLE ac9bc819bc438f21bd38a995812d756727ed8e2a
+# SKIP-SINGLE 7d7e9ef46a1b310fb3f481cdf8023082f5ec1618
+# SKIP-SINGLE d6362b632e3c76cb55a05248aa221e426c5adb5a
+# SKIP-SINGLE 00df4566af9dff0a27fd6da566ef1e53268a6d47
+# SKIP-SINGLE 655957087c8654577e7c59004f16be7abcc2c46c
+# SKIP-SINGLE e41af3971de8f71b5241698a8b29349905f1a969
+# SKIP-SINGLE 59eaa30b07e9a79a9b2bb6ade0be9aac846384e2
+# SKIP-SINGLE 5d77eb4b7c00d0652b190166c393efa16d0775a9
+# SKIP-SINGLE c6384e9bfbc765229ea9676ba1044b9db28fec2d
+# SKIP-SINGLE 409f0430b6a0c138836e5067141bf6b2a7beb6b3
+# SKIP-SINGLE 2f03053e568f38a1dce5ffe02ad1359069ef84c8
+# SKIP-SINGLE d5c6d69b4fea2d5a1167a0bcc0b9994a5939b97e
+# SKIP-SINGLE 28490cd65ba50ce4e1f411556e1faa36f1db84ec
+# SKIP-SINGLE d06127e5736b0564daf99a41c77c8c23d394e759
+# SKIP-SINGLE b440fa0a6b48a95323fa922b88e9a9a73d6c6360
+# SKIP-SINGLE 62e37ecc4020b3a5b18cfdcff9a7cb259fd8145a
+# SKIP-SINGLE ddbc33343cca8c66d841cc16eac77ea626e50e23
+# SKIP-SINGLE 902649a170ab651cffe2bbb421e1331b23c7ed01
+# SKIP-SINGLE 7bc615fd23c1304f8682f2443db235fbc37bfde9
+# SKIP-SINGLE 7f57d80846b5f674c49a717d6fc086c14f506415
+# SKIP-SINGLE 639821d49ab9497908d8d3bcd472aed558c251e1
+# SKIP-SINGLE 75b65b3f67eb9a4e5722780cb915b880e667d674
+# SKIP-SINGLE 306e49285a04c02f0a575a7d7b2f82eeb032c86b
+# SKIP-SINGLE d1ef0243eb6e7cd9720236eb0e900fe7163b3c2b
+# SKIP-SINGLE 162c3da7a0ae4cb5e1b0e34731621ec13ac01e43
+# SKIP-SINGLE ab70ab19be64902123b0e2c08191d5ebf70feb62
+# SKIP-SINGLE 8175497ccac1b3afc2208260be91423e2bca2d25
+# SKIP-SINGLE 63f8a838eccf201d6290d0dc8f83881f41785afb
+# SKIP-SINGLE e0760599b045a7ef3828ae4b624246b6beec2e75
+# SKIP-SINGLE 34e50dc4a23505dce0499f120477e2e1a1327432
+# SKIP-SINGLE 06db8015ea05cc17efb16684de23533ee315be61
+# SKIP-SINGLE ecb216fd93dc959bda283d27d759b253ee0e2798
+# SKIP-SINGLE 0d195584f20bba1c1de165fbc4162417737755c4
+# SKIP-SINGLE 829c7e3566ed425c0204067c654a58970af6d4fe
+# SKIP-SINGLE 7e9c2e295283b4dcf4f88cf25a094e37731543fc
+# SKIP-SINGLE 3a0c94ac0b5d5098f9140c5ab4231d6dd06ec393
+# SKIP-SINGLE 3a5c4bdc0c079f72bad98e01f70343ba9e9b0043
+# SKIP-SINGLE 908aab6144bf9f62dd5b2c2f1776ed177fa6d18f
+# SKIP-SINGLE c78dc25a5351b1a4191028ba252c892ae1dd2438
+# SKIP-SINGLE 67f9705fc0fc5ecc91172ab02df8c1f31fe654e2
+# SKIP-SINGLE 25c6bc7a3d3679b26406bbcac33954186db491f2
+# SKIP-SINGLE faf44e2c61734cfe2422498ed27b4f645635120d
+# SKIP-SINGLE e333f040e9f68bdce2b5735b4b9dd68944199056
+# SKIP-SINGLE 5cd3db73bed06e394ea8e7b0e332b1b1e5bd9571
+# SKIP-SINGLE 4489450f37deafb013b1f0fc00c89f0973fda14a
+# SKIP-SINGLE 98ed6db34f76cfe37d70d8ad82d29fcfa2a56e24
+# SKIP-SINGLE 2ec403f777adf39d3e972667513086f2053530dd
+# SKIP-SINGLE c5e3b99467dd07522f9522cc77cddbaa69222a7b
+# SKIP-SINGLE ab4edbf60eca767775e18d8d0e318c28a74792b3
+# SKIP-SINGLE a5a047a07f2d4f98fc67b40eb1f1a1d711905381
+# SKIP-SINGLE f5084ed197cfea8387ffa7dd72b72933905fe699
+# SKIP-SINGLE e06953b02a0e7b26b33c511a22896d0db4e5d63d
+# SKIP-SINGLE 77cb95c851edc338c94cb35effdc8c9ffc64a461
+# SKIP-SINGLE eecc2d45b94513ba95789dfe0ef58aeb8b029049
+# SKIP-SINGLE 663d768d44be150439a58cd858615cac3c1f572f
+# SKIP-SINGLE 838fc77254286de318b65602b31c6d3915594a8e
+# SKIP-SINGLE a7042fa051c69b8c647fce3ec52b74974b5ea2be
+# SKIP-SINGLE 2332c3eb55b2c8541ea83d4a847c56f888239f6a
+# SKIP-SINGLE 077c66405261381704da33e6858f4b6639763f5a
+# SKIP-SINGLE 2b4d46f99be3735823666c2a6d9f058cedeb031c
+# SKIP-SINGLE 5858921f409f6ee9d2e08dbdcd1719969a4f5544
+# SKIP-SINGLE 29418f954eb114bf3c108b6e03569036f854ae45
+# SKIP-SINGLE 07292b1344549a164eff9d548f819235a14a0b4e
+# SKIP-SINGLE 1bed1f0b8e9095d66f905ed7b409a397f1972262
+# SKIP-SINGLE 98f5b74808a54ad9093888b72b2c04e085f4b369
+# SKIP-SINGLE 1ae314dfda1a7746fb31957ac3eedefd70b3c1fe
+# SKIP-SINGLE 488a6efe323927a4064afc193b66cd11e2caf77c
+# SKIP-SINGLE 9fbbb2355298f75e8fd09b35306e843ce45b9e25
+# SKIP-SINGLE 076a25810127cb8c56ff0f5272a3d8b98192ee77
+# SKIP-SINGLE f847ecc40bc768d97ba57083fd669ca0104e500f
+# SKIP-SINGLE b471f7f6141b3db8fb00f62f12900846f59beb9a
+# SKIP-SINGLE 5fbb7a126d19b41848b57e7e012619fa13cfa4d2
+# SKIP-SINGLE d4e8c90b66b4aba66ff1a12a0894a33af91feb0e
+# SKIP-SINGLE 243ee7b244797aae460b9e2a7224f75599f3a9b8
+# SKIP-SINGLE 951dd2a4d98aafe88bf2c6c2f86901230e3f0cd2
+# SKIP-SINGLE c924b6afb6810d6b9585092fc5693e3c9efcd1cf
+# SKIP-SINGLE ce9e7204138261f71d0e1636036727d8b05ac81e
+# SKIP-SINGLE e0e3299c01d3ad7236a7a950f43f54a1bff548d8
+# SKIP-SINGLE 784f53a2152181b687f9543ddba9c393dda1c715
+# SKIP-SINGLE 673a55780d2194f74c5774de83d0dce5131e7a31
+# SKIP-SINGLE 8ad4c4009e1c7360df6f59175b1a701d7f4ecfae
+# SKIP-SINGLE d9d66764e2a02db9f19f5c76ce34ac7d8bc1edc6
+# SKIP-SINGLE f6dc55f516a88765bbd8b8c34f0ec663b8948373
+# SKIP-SINGLE b86deb617b109bcb40e9c95b10a033a209c1d8fd
+# SKIP-SINGLE c5f24f76eb1653d64c2ae90764e395cf6e050657
+# SKIP-SINGLE b028d4f7dfbd72790679423a8dcce9994b07834d
+# SKIP-SINGLE e3663d0e9c6ec32a70226947767850924b90bba7
+# SKIP-SINGLE f9f9b43df5bdadb54a1ba14e1624aa254d9f092d
+# SKIP-SINGLE 5416ae5990337f5fb2b3e0fbf9c4575508da808e
+# SKIP-SINGLE 99096528494a653d1ee9d7832ee3956a613aeb95
+# SKIP-SINGLE 6b91ea5a6159791d1d1e5006f8cbc384c0da1701
+# SKIP-SINGLE bd8e19e1e2ccfb76c1fccc4dff1f8774185cfea4
+# SKIP-SINGLE 88d54756d46101b97b7fde97b4bc3b62f7bd6c06
+# SKIP-SINGLE 32e87f09c8c2711c421363d0361693dcfbe5a688
+# SKIP-SINGLE 69ab588bb54178df0d3be6b4c04dabb49f5a2ac9
+# SKIP-SINGLE f331be1f074d68e7e5cdbac324419e07c186492a
+# SKIP-SINGLE 040991a4697b50ebcb54e498e7de54b8d0885101
+# SKIP-SINGLE 5070278539a8e47988cd9529c9c2e4ada8c92472
+# SKIP-SINGLE 0be9a639fca70c278d1b79fcea5d6beebdf7799c
+# SKIP-SINGLE 31f75430999b9021fc68739af231261608aac255
+# SKIP-SINGLE 77f1533ccbba1a5dc0824770046696181a2b7b6c
+# SKIP-SINGLE 57e37e9128b4f6f9a2aae0bc25de6c208d58e5d0
+# SKIP-SINGLE c6dce90d7e57486db687606bffd92d580a7d25ca
+# SKIP-SINGLE c88a1631e3f76926bf0fed49fa1b704d6eaf2155
+# SKIP-SINGLE 8607f018fd8bef7443415ff2e356d035843ad828
+# SKIP-SINGLE 1cd42bfb8a5ff2aade43f31b864a8d2cd643d5a3
+# SKIP-SINGLE f0e9085a17be8866c123b120e3252c52845ec38e
+# SKIP-SINGLE 9d3f8912b431ed5540d9d06d85b7e338732268c9
+# SKIP-SINGLE c8909fa3688aca164e4fd38f6293c4a201e148eb
+# SKIP-SINGLE 10f96a8c57b031b521ae8ba5a02413b94ece423b
+# SKIP-SINGLE c2ecb08775dc24618de507d2d1ce0f9b0debe17e
+# SKIP-SINGLE cb183f6467401fb5ed2b7fc98ca75be9d943cbe3
+# SKIP-SINGLE 76b86d98534da2c9e6cf8fd1c7edcbe53d84eb82
+# SKIP-SINGLE 85073998cb47567cb30fb41f12135bd799ad2588
+# SKIP-SINGLE f1e058d46b5a83ddd0423a3616aa50ac3ec7f551
+# SKIP-SINGLE f46eb3d3ca759ab3944cedda1339a6d1760298cd
+# SKIP-SINGLE 9fab83ed7a90209e3873039e7ae4993c667e2759
+# SKIP-SINGLE c957832cbf3e87e5a25f7c2bdb70abd959391d98
+# SKIP-SINGLE e5043db2f1f3d0ce6618eb45419e85f0d58fbf19
+# SKIP-SINGLE e8df6c311fcf59bf23d31b9db2bb8fec9d78fbe7
+# SKIP-SINGLE da87895df2d6b21468b187f5a4e2ca8710e35ee7
+# SKIP-SINGLE 6203b9db347d2d002c0cb660d5b4daeea54bf3ad
+# SKIP-SINGLE f6e92035a7c3c29aa980e1bebf9c48f1bb7264d8
+# SKIP-SINGLE 7ebbd4efc3d45403cf845d35c36c21756baeeba8
+# SKIP-SINGLE b584569014abb1fe9f59decd86ea097a189d9bb5
+# SKIP-SINGLE 17422c2cfcbf1670ba4dbe3ecdf3c5ff719201cc
+# SKIP-SINGLE 2349ecb3216bb9f7808ac58e5ce6abd6bcf90387
+# SKIP-SINGLE 6fb6cb075f05629a562275064851bef6b72d5dd2
+# SKIP-SINGLE 6a2399c55e9505be06cb98ffbe1a3878f9e96fb2
+# SKIP-SINGLE 4ba76224eaf5fade94438bf990bf5eb05912b530
+# SKIP-SINGLE 77e6a704ac819580b81400ff1d8503d142cb3905
+# SKIP-SINGLE 524d10c86b539ef6fe27f31ed3df2590d1849a83
+# SKIP-SINGLE baacad1771e3551ffdb1b88c41224fa1957e766c
+# SKIP-SINGLE 9ed53535f5543910f746662618927052dd718991
+# SKIP-SINGLE f6483526cd4b4b9ed7d830599add82ecb45009e6
+# SKIP-SINGLE c4122067d90857594508f6c00e8af87d91ddb7d4
+# SKIP-SINGLE 1bb7b43e1cfb911737bc4807671910238277470f
+# SKIP-SINGLE 5532ae81cff138a2f6d30c3541210311a4894ac1
+# SKIP-SINGLE ccd2509ed31f953408240357e9b84c3d3b3f6a2b
+# SKIP-SINGLE bc66ff98756fa28bbc733ef81103cac6730438fa
+# SKIP-SINGLE 9b5ecffeb00f22ca6663aa14e7807c9886ed1716
+# SKIP-SINGLE bb8376145abadd901b0d8f7f586bef658e2b333c
+# SKIP-SINGLE 092776c7ebf20b4d1208a0e0d860a1f3abd7d119
+# SKIP-SINGLE 434fc2a22e4fd65fd63018e9373cbf56b51f8ab2
+# SKIP-SINGLE 591759d508024a666a863cf918287744e72b1267
+# SKIP-SINGLE 75c8cc5eab51d1080424687167fec4feb34f68c1
+# SKIP-SINGLE f6e3de3f63616d7bd52c1390f9dea70fa33e49c2
+# SKIP-SINGLE bb8a46e559ec39437a1524b3e9746746768effcc
+# SKIP-SINGLE 52c8fdde1667ac4b5d7f2af5eff94d6512d83caa
+# SKIP-SINGLE 8bc6e31502244ca16bbf7b163a7a321ec9094882
+# SKIP-SINGLE 3a4406975338eb6dad9327b5d17f67a677114e6a
+# SKIP-SINGLE 02f78c09b0a97ba044a43682a366a9d7732b885d
+# SKIP-SINGLE 954b6e1dc3edb6a8260be810c3f02c335e90b6b8
+# SKIP-SINGLE 79ee266f13fa5c657b24dc45d5f573c393a671b6
+# SKIP-SINGLE c4179117afd37a03a7ba322e66b5bd6bae5637bd
+# SKIP-SINGLE 45b8204e09b7d399b792bb26c799efe48835c4a7
+# SKIP-SINGLE 2a762336da4d886a4f1b3ee463fd66393d739309
+# SKIP-SINGLE e45d8dbeea488ac14fe486e5582266980d29e82c
+# SKIP-SINGLE 253126bf339a16589e86acd51c0f96da07e658d9
+# SKIP-SINGLE e868955bff3b97bad88bd09b4401e87cab94011c
+# SKIP-SINGLE 6e60d464188994bdce97f1aef3b81fae3fd28583
+# SKIP-SINGLE 5868580e94ed93ce4f0ec88b03b232f5cd29178d
+# SKIP-SINGLE 18947103fabf8070738b3bd9c5a8d02f90988a3d
+# SKIP-SINGLE 3114eb807864e19cd8ffdc5d8f8e11366a619769
+# SKIP-SINGLE c352392420236d4fa7a8ac7f324f1a0358ad3584
+# SKIP-SINGLE a915d836fce238cd57233f67e8d2451a26d2fb6b
+# SKIP-SINGLE 5c1b9e65b9d1c73ccc4ce18842d10bc507cdee38
+# SKIP-SINGLE 57b904f4bab7aea7ddb9d3b36229008a47b32ff1
+# SKIP-SINGLE 2f6b017e3dc646d317b56fb453c90aaa44c27089
+# SKIP-SINGLE fa9bede36c18d063f6f599e102cd42f9d0afc071
+# SKIP-SINGLE 0c7a7df98e1fb0bc156707b379e4147fac97359a
+# SKIP-SINGLE 0480e9c445d59fd5ec9b38ebe3919fee2aabf8d2
+# SKIP-SINGLE 5a2c1a743b54f7d3355f9b1dc893bbe72e8df6bc
+# SKIP-SINGLE 629f222ba2abf5a149c381e27c89e88963f7466d
+# SKIP-SINGLE ef6e18a6b9ab103f3f076b35100d09cff1687396
+# SKIP-SINGLE 9e339415b4c068242e7cd785d2ac95420f1934ba
+# SKIP-SINGLE 8c385f05120bdf905a027fe99eab23a59d0f837e
+# SKIP-SINGLE c4ad36cd2daab764649db451c4a3f1a35c5f519a
+# SKIP-SINGLE b755f45f65090665dd40ed0f0dc4eb6f9e4923a0
+# SKIP-SINGLE 1ea503ed4b3a14b3dc0a597cfbfe57d73b871422
+# SKIP-SINGLE eba65824364474bde89bdce5f57a772d74a2c409
+# SKIP-SINGLE 17b65f52921b6a9314a2709f0e5c3ef88b37f2ab
+# SKIP-SINGLE 170924e945f4cceda12b5e1681391c3b828a3dec
+# SKIP-SINGLE cea1e95d386270e1e682719232f2cfad384fab91
+# SKIP-SINGLE b341864d9002fd081a8a6dfeb5a5a00373738a2f
+# SKIP-SINGLE 6cf2a9c55dbf8dfbc93409340065cf02881502b1
+# SKIP-SINGLE 50e33639fe190f0a1c47b8e4c0fcc4735cb60909
+# SKIP-SINGLE af288d813b3c31a528ddcbdce08f497855a56e94
+# SKIP-SINGLE 007d8c485906be46d40e74ddb8046e065c722786
+# SKIP-SINGLE 08a1c32d0bcaa9369a34e7f7d6d01c3885f62e21
+# SKIP-SINGLE ceb9591e5dcb5264573371a573433fd76320954e
+# SKIP-SINGLE 1787e651d376486909e736478b1be92c949a368d
+# SKIP-SINGLE 734df28368c7f7c21b1068a67d4ae89e64d4a3d3
+# SKIP-SINGLE c5147882a91e51b59c7da035e9ef38a4731b943d
+# SKIP-SINGLE 6b475da972d7e2ff7a2a3cafc1aea2a4937e64e9
+# SKIP-SINGLE 7e36fd64d2ce06b821e0f57f6d850ff4386608bf
+# SKIP-SINGLE c120b0ebdb20cfff73dd1d43541f1ba1bbc54b74
+# SKIP-SINGLE 0b3f785c4a272b909108108cf7931779ae48cfba
+# SKIP-SINGLE f071e61d106e6f3c17b660e3aa1a5b7890ea5d41
+# SKIP-SINGLE 6a3caeab580f61f88c4ad49ff32cdf74eea4fb97
+# SKIP-SINGLE 06b5ec4bbde119d14d866fc3713a4ed390d531f2
+# SKIP-SINGLE 795e01ac248d389a581589b13a02465a2f99202f
+# SKIP-SINGLE aaaa4ca77e440499ec852069efaea42410ebe30b
+# SKIP-SINGLE 6f28810f6ba112059c09bc3bfbb2ef8e5c3f15ee
+# SKIP-SINGLE 773cce640fc5d67cb1a64622defa073d7ec5fcc4
+# SKIP-SINGLE 260e47e9a3c9b3baecef81e69c218989dc0cd7a4
+# SKIP-SINGLE e504eabe88727141e70ae9793be71d4285f839a5
+# SKIP-SINGLE eeeae5e9ee34da5539046ff8dac4f4fffa19a5b9
+# SKIP-SINGLE 861e1fb595eb1f01ca5c137fb4830695f9c1e7d2
+# SKIP-SINGLE 7c5d4348330b206aff1f8e5bc4fd241d6a6dc0b5
+# SKIP-SINGLE 1575ee2eeb1ebb5b73b4b76fc7dc7f5702748540
+# SKIP-SINGLE ce5ae0117e3ea009ccdd8d8f4c1365301d24f90b
+# SKIP-SINGLE 851a8f65e9a6b00b51f6a41f4c8f2ec2a797862b
+# SKIP-SINGLE 5159789e55d64c7482dff3dc1a621d01f530f83c
+# SKIP-SINGLE 25cb49ad565c764c390a411661088970db1f2b22
+# SKIP-SINGLE 9c4dddad456e23892a80303da26774a13250b647
+# SKIP-SINGLE 4c328daf0130fc139e827a8a8d6689e2b15c73ea
+# SKIP-SINGLE 1ee7c3041ac84b6c6f3f4f5275c417d91727312e
+# SKIP-SINGLE c9df4cace0f88197e69ae45d18bfc1692eecca05
+# SKIP-SINGLE b49250ada978c7b21cb93177c874c81a27fa4fec
+# SKIP-SINGLE 377ee8158b2fab3efccb4e9b262e6129b51e28f8
+# SKIP-SINGLE bd13ce184bfaf43f905faff64c5306ff3518f892
+# SKIP-SINGLE 914f68da059d5aeed3459e3944769aa4370a4075
+# SKIP-SINGLE e7b09065dae0aa8018c959ad3c69626bbcce8f17
+# SKIP-SINGLE 9f7c359f4023570616c9961487069ba1122a5bb0
+# SKIP-SINGLE a3651d3237e91f788211e507d61c2dcf886c185f
+# SKIP-SINGLE 62c8c8e51a23540cd189d6b2a22dd1a1cdbbf2cb
+# SKIP-SINGLE 7a4380b9051ddd0bcc4d5c90abe0f826a9b922dc
+# SKIP-SINGLE 23bb724c922de95573f73b22ae311696ae08464e
+# SKIP-SINGLE ddae8d4a13d58720a3118355fabc225a9d907160
+# SKIP-SINGLE a31538ea5b006c3901ab85354725993b689a259d
+# SKIP-SINGLE 1cdb24fe35a9ff2e4f92c5acc93a5a5b0e70d93f
+# SKIP-SINGLE 7c750343be6309a78d3fd289959bca241d9daf5d
+# SKIP-SINGLE bde8e87cb7b3be0e0bc9e72c3634f108570cac3e
+# SKIP-SINGLE 013c7d6aaef5f90730b1cfe42a01534d891e895a
+# SKIP-SINGLE 85d0c11119fbd14d508d228f5edf4cf53fb4e4cb
+# SKIP-SINGLE 53584db07ed3411d659678425c4481997e56c834
+# SKIP-SINGLE bb0a427e9d3c29c17c1b03773697989328f53056
+# SKIP-SINGLE 4ef50ccd3f8bc177ef6dd7183a9268bb8057f064
+# SKIP-SINGLE 285f8c7cfecee0c91568cd850139c48ec3f21a28
+# SKIP-SINGLE 96d44c4321724556819e2f718f1d94470d753d07
+# SKIP-SINGLE 1f74e9112e28faa57a7bf56547a9ebf8f6618273
+# SKIP-SINGLE 3a784d1321487be4031555d19ace635598bba21c
+# SKIP-SINGLE 4552b01d8c8052f607dca2fcddcf7b2e270f1db6
+# SKIP-SINGLE b6568c1389128d47538b646d940427949ddf58d0
+# SKIP-SINGLE 6d5b34d9de7b2f1b346d9aff123ad20c942166dc
diff --git a/admin/make-tarball.txt b/admin/make-tarball.txt
index d881b81612..45da3ed6be 100644
--- a/admin/make-tarball.txt
+++ b/admin/make-tarball.txt
@@ -150,6 +150,12 @@ General steps (for each step, check for possible errors):
 4.    autoreconf -i -I m4 --force
       make bootstrap
 
+      ./admin/check-man-pages
+
+    The above script checks for any mistakes in the source text of
+    manual pages.  Fix any errors and re-run the script to verify.
+    Then do this:
+
       make -C etc/refcards
       make -C etc/refcards clean
 
diff --git a/admin/merge-gnulib b/admin/merge-gnulib
index d3c5520ad0..99f834b0ae 100755
--- a/admin/merge-gnulib
+++ b/admin/merge-gnulib
@@ -33,13 +33,14 @@ GNULIB_MODULES='
   crypto/md5 crypto/md5-buffer
   crypto/sha1-buffer crypto/sha256-buffer crypto/sha512-buffer
   d-type diffseq double-slash-root dtoastr dtotimespec dup2
-  environ execinfo explicit_bzero faccessat
+  environ execinfo faccessat
   fchmodat fcntl fcntl-h fdopendir file-has-acl
   filemode filename filevercmp flexmember fpieee
   free-posix fstatat fsusage fsync futimens
   getloadavg getopt-gnu getrandom gettime gettimeofday gitlog-to-changelog
   ieee754-h ignore-value intprops largefile libgmp lstat
-  manywarnings memmem-simple mempcpy memrchr minmax mkostemp mktime
+  manywarnings memmem-simple mempcpy memrchr memset_explicit
+  minmax mkostemp mktime
   nanosleep nproc nstrftime
   pathmax pipe2 pselect pthread_sigmask
   qcopy-acl readlink readlinkat regex
diff --git a/admin/notes/git-workflow b/admin/notes/git-workflow
index 265a106bad..d33f49a1ac 100644
--- a/admin/notes/git-workflow
+++ b/admin/notes/git-workflow
@@ -16,14 +16,14 @@ Initial setup
 
 Then we want to clone the repository.  We normally want to have both
 the current master and (if there is one) the active release branch
-(eg emacs-28).
+(eg emacs-29).
 
 mkdir ~/emacs
 cd ~/emacs
 git clone <membername>@git.sv.gnu.org:/srv/git/emacs.git master
 cd master
 git config push.default current
-git worktree add ../emacs-28 emacs-28
+git worktree add ../emacs-29 emacs-29
 
 You now have both branches conveniently accessible, and you can do
 "git pull" in them once in a while to keep updated.
@@ -67,7 +67,7 @@ which will look like
 
 commit 958b768a6534ae6e77a8547a56fc31b46b63710b
 
-cd ~/emacs/emacs-28
+cd ~/emacs/emacs-29
 git cherry-pick -xe 958b768a6534ae6e77a8547a56fc31b46b63710b
 
 and add "Backport:" to the commit string.  Then
@@ -109,7 +109,7 @@ up-to-date by doing a pull.  Then start Emacs with
   emacs -l admin/gitmerge.el -f gitmerge
 
 You'll be asked for the branch to merge, which will default to
-(eg) 'origin/emacs-28', which you should accept.  Merging a local tracking
+(eg) 'origin/emacs-29', which you should accept.  Merging a local tracking
 branch is discouraged, since it might not be up-to-date, or worse,
 contain commits from you which are not yet pushed upstream.
 
diff --git a/admin/notes/repo b/admin/notes/repo
index 97f02ab605..2be707db27 100644
--- a/admin/notes/repo
+++ b/admin/notes/repo
@@ -129,8 +129,12 @@ This is a semi-automated way to find the revision that 
introduced a bug.
 Browse 'git help bisect' for technical instructions.
 
 It is recommended to start a bisection with the admin/git-bisect-start
-script.  This script prunes the branches that are the result of
-merging external trees into the Emacs repository.
+script.  Using that script ensures that commits in branches that are
+the result of merging external trees into the Emacs repository, as
+well as certain commits on which Emacs fails to build, are skipped
+during the bisection process.  That script can also be executed
+automatically when 'git bisect start' is called, with the help of a
+wrapper script that is included in its commentary section.
 
 * Maintaining ChangeLog history
 
diff --git a/admin/notes/tree-sitter/build-module/batch.sh 
b/admin/notes/tree-sitter/build-module/batch.sh
index deed18978a..58272c7454 100755
--- a/admin/notes/tree-sitter/build-module/batch.sh
+++ b/admin/notes/tree-sitter/build-module/batch.sh
@@ -1,17 +1,24 @@
 #!/bin/bash
 
 languages=(
+    'bash'
     'c'
+    'cmake'
     'cpp'
     'css'
     'c-sharp'
+    'dockerfile'
     'go'
+    'go-mod'
     'html'
     'javascript'
     'json'
     'python'
     'rust'
+    'toml'
+    'tsx'
     'typescript'
+    'yaml'
 )
 
 for language in "${languages[@]}"
diff --git a/admin/notes/tree-sitter/build-module/build.sh 
b/admin/notes/tree-sitter/build-module/build.sh
index 102ab310fa..f096294028 100755
--- a/admin/notes/tree-sitter/build-module/build.sh
+++ b/admin/notes/tree-sitter/build-module/build.sh
@@ -1,6 +1,7 @@
 #!/bin/bash
 
 lang=$1
+topdir="$PWD"
 
 if [ $(uname) == "Darwin" ]
 then
@@ -11,25 +12,49 @@ fi
 
 echo "Building ${lang}"
 
-# Retrieve sources.
-git clone "https://github.com/tree-sitter/tree-sitter-${lang}.git"; \
+### Retrieve sources
+
+org="tree-sitter"
+repo="tree-sitter-${lang}"
+sourcedir="tree-sitter-${lang}/src"
+grammardir="tree-sitter-${lang}"
+
+case "${lang}" in
+    "dockerfile")
+        org="camdencheek"
+        ;;
+    "cmake")
+        org="uyha"
+        ;;
+    "go-mod")
+        # The parser is called "gomod".
+        lang="gomod"
+        org="camdencheek"
+        ;;
+    "typescript")
+        sourcedir="tree-sitter-typescript/typescript/src"
+        grammardir="tree-sitter-typescript/typescript"
+        ;;
+    "tsx")
+        repo="tree-sitter-typescript"
+        sourcedir="tree-sitter-typescript/tsx/src"
+        grammardir="tree-sitter-typescript/tsx"
+        ;;
+    "yaml")
+        org="ikatyang"
+        ;;
+esac
+
+git clone "https://github.com/${org}/${repo}.git"; \
     --depth 1 --quiet
-if [ "${lang}" == "typescript" ]
-then
-    lang="typescript/tsx"
-fi
-cp tree-sitter-lang.in "tree-sitter-${lang}/src"
-cp emacs-module.h "tree-sitter-${lang}/src"
-cp "tree-sitter-${lang}/grammar.js" "tree-sitter-${lang}/src"
-cd "tree-sitter-${lang}/src"
+cp "${grammardir}"/grammar.js "${sourcedir}"
+# We have to go into the source directory to compile, because some
+# C files refer to files like "../../common/scanner.h".
+cd "${sourcedir}"
 
-if [ "${lang}" == "typescript/tsx" ]
-then
-    lang="tsx"
-fi
+### Build
 
-# Build.
-cc -c -I. parser.c
+cc -fPIC -c -I. parser.c
 # Compile scanner.c.
 if test -f scanner.c
 then
@@ -48,15 +73,9 @@ else
     cc -fPIC -shared *.o -o "libtree-sitter-${lang}.${soext}"
 fi
 
-# Copy out.
-
-if [ "${lang}" == "typescript" ]
-then
-    cp "libtree-sitter-${lang}.${soext}" ..
-    cd ..
-fi
+### Copy out
 
-mkdir -p ../../dist
-cp "libtree-sitter-${lang}.${soext}" ../../dist
-cd ../../
-rm -rf "tree-sitter-${lang}"
+mkdir -p "${topdir}/dist"
+cp "libtree-sitter-${lang}.${soext}" "${topdir}/dist"
+cd "${topdir}"
+rm -rf "${repo}"
diff --git a/admin/notes/tree-sitter/starter-guide 
b/admin/notes/tree-sitter/starter-guide
index 123dabd9f2..a6a4c647f2 100644
--- a/admin/notes/tree-sitter/starter-guide
+++ b/admin/notes/tree-sitter/starter-guide
@@ -282,7 +282,7 @@ For MATHCER we have
            NODE-INDEX-MIN NODE-INDEX-MAX)
 
     => checks everything. If an argument is nil, don’t match that. Eg,
-    (match nil nil TYPE) is the same as (parent-is TYPE)
+    (match nil TYPE) is the same as (parent-is TYPE)
 
 For ANCHOR we have
 
diff --git a/configure.ac b/configure.ac
index 9f431fc78b..5bd6645a25 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1841,7 +1841,9 @@ AC_CHECK_HEADERS_ONCE(
   coff.h pty.h
   sys/resource.h
   sys/utsname.h pwd.h utmp.h util.h
-  sanitizer/lsan_interface.h])
+  sanitizer/lsan_interface.h
+  sanitizer/asan_interface.h
+  sanitizer/common_interface_defs.h])
 
 AC_CACHE_CHECK([for ADDR_NO_RANDOMIZE],
   [emacs_cv_personality_addr_no_randomize],
@@ -3933,21 +3935,10 @@ if test "${HAVE_X11}" = "yes"; then
   if test "${HAVE_XCB}" = "yes"; then
     AC_CHECK_LIB([X11-xcb], [XGetXCBConnection], [HAVE_X11_XCB=yes])
     if test "${HAVE_X11_XCB}" = "yes"; then
-      AC_CHECK_LIB([xcb-util], [xcb_aux_sync], [HAVE_XCB_UTIL=yes])
-      if test "${HAVE_XCB_UTIL}" = "yes"; then
-       AC_DEFINE([USE_XCB], [1],
+      AC_DEFINE([USE_XCB], [1],
 [Define to 1 if you have the XCB library and X11-XCB library for mixed
-  X11/XCB programming.])
-        XCB_LIBS="-lX11-xcb -lxcb -lxcb-util"
-      else
-       AC_CHECK_LIB([xcb-aux], [xcb_aux_sync], [HAVE_XCB_AUX=yes])
-        if test "${HAVE_XCB_AUX}" = "yes"; then
-         AC_DEFINE([USE_XCB], [1],
-[Define to 1 if you have the XCB library and X11-XCB library for mixed
- X11/XCB programming.])
-          XCB_LIBS="-lX11-xcb -lxcb -lxcb-aux"
-        fi
-      fi
+X11/XCB programming.])
+      XCB_LIBS="-lX11-xcb -lxcb"
     fi
   fi
 fi
@@ -5008,6 +4999,7 @@ pthread_sigmask strsignal setitimer \
 sendto recvfrom getsockname getifaddrs freeifaddrs \
 gai_strerror sync \
 getpwent endpwent getgrent endgrent \
+renameat2 \
 cfmakeraw cfsetspeed __executable_start log2 pthread_setname_np \
 pthread_set_name_np])
 LIBS=$OLD_LIBS
@@ -6000,7 +5992,7 @@ case $opsys in
   gnu-linux | gnu-kfreebsd )
     AC_DEFINE([USG], [])
     AC_DEFINE([GNU_LINUX], [],
-      [Define if ths system is compatible with GNU/Linux.])
+      [Define if this system is compatible with GNU/Linux.])
     ;;
 
   hpux*)
diff --git a/doc/emacs/macos.texi b/doc/emacs/macos.texi
index 1457a8bc3a..96f881ca12 100644
--- a/doc/emacs/macos.texi
+++ b/doc/emacs/macos.texi
@@ -154,7 +154,7 @@ titlebar.
 @vindex ns-confirm-quit
 @item ns-confirm-quit
 This variable specifies whether to display a graphical confirmation
-dialogue on quitting.
+dialog on quitting.
 
 @vindex ns-auto-hide-menu-bar
 @item ns-auto-hide-menu-bar
diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi
index 29c0bed19c..702c72bac2 100644
--- a/doc/emacs/misc.texi
+++ b/doc/emacs/misc.texi
@@ -1808,31 +1808,28 @@ you can give each daemon its own server name like this:
   emacs --daemon=foo
 @end example
 
-@findex server-stop-automatically
+@vindex server-stop-automatically
   The Emacs server can optionally be stopped automatically when
-certain conditions are met.  To do this, call the function
-@code{server-stop-automatically} in your init file (@pxref{Init
-File}), with one of the following arguments:
+certain conditions are met.  To do this, set the option
+@code{server-stop-automatically} to one of the following values:
 
-@itemize
-@item
-With the argument @code{empty}, the server is stopped when it has no
-clients, no unsaved file-visiting buffers and no running processes
-anymore.
-
-@item
-With the argument @code{delete-frame}, when the last client frame is
-being closed, you are asked whether each unsaved file-visiting buffer
-must be saved and each unfinished process can be stopped, and if so,
-the server is stopped.
-
-@item
-With the argument @code{kill-terminal}, when the last client frame is
-being closed with @kbd{C-x C-c} (@code{save-buffers-kill-terminal}),
-you are asked whether each unsaved file-visiting buffer must be saved
-and each unfinished process can be stopped, and if so, the server is
+@table @code
+@item empty
+This value causes the server to be stopped when it has no clients, no
+unsaved file-visiting buffers and no running processes anymore.
+
+@item delete-frame
+This value means that when the last client frame is being closed, you
+are asked whether each unsaved file-visiting buffer must be saved and
+each unfinished process can be stopped, and if so, the server is
 stopped.
-@end itemize
+
+@item kill-terminal
+This value means that when the last client frame is being closed with
+@kbd{C-x C-c} (@code{save-buffers-kill-terminal}), you are asked
+whether each unsaved file-visiting buffer must be saved and each
+unfinished process can be stopped, and if so, the server is stopped.
+@end table
 
 @findex server-eval-at
   If you have defined a server by a unique server name, it is possible
diff --git a/doc/emacs/programs.texi b/doc/emacs/programs.texi
index ba8475e86a..3812c2aa28 100644
--- a/doc/emacs/programs.texi
+++ b/doc/emacs/programs.texi
@@ -88,6 +88,10 @@ mode for the C programming language is @code{c-mode}.
 @cindex JSON mode
 @cindex SQL mode
 @cindex TypeScript mode
+@cindex CSS mode
+@cindex Dockerfile mode
+@cindex CMake mode
+@cindex TOML mode
   Emacs has programming language modes for Lisp, Scheme, the
 Scheme-based DSSSL expression language, Ada, ASM, AWK, C, C++, C#,
 Fortran, Icon, IDL (CORBA), IDLWAVE, Java, Javascript, M4, Makefiles,
@@ -97,13 +101,20 @@ Python, Ruby, Simula, SQL, Tcl, TypeScript, Verilog, and 
VHDL@.  An
 alternative mode for Perl is called CPerl mode.  Modes are also
 available for the scripting languages of the common GNU and Unix
 shells, and MS-DOS/MS-Windows @samp{BAT} files, JSON, DNS master
-files, and various sorts of configuration files.
+files, CSS (Cascading Style Sheets), Dockerfiles, CMake files, and various 
sorts of configuration files.
 
   Ideally, Emacs should have a major mode for each programming
 language that you might want to edit.  If it doesn't have a mode for
 your favorite language, the mode might be implemented in a package not
 distributed with Emacs (@pxref{Packages}); or you can contribute one.
 
+@cindex tree-sitter library, supported major modes
+  If Emacs has been compiled with the @samp{tree-sitter} library, it
+offers several optional editing modes based on that library, which
+utilize the incremental parsing capabilities provided by
+@samp{tree-sitter}.  These modes have @samp{-ts-} in their names; for
+example @code{c-ts-mode}, @code{python-ts-mode}, etc.
+
 @kindex DEL @r{(programming modes)}
 @findex backward-delete-char-untabify
   In most programming languages, indentation should vary from line to
@@ -409,6 +420,9 @@ large chunks of code:
 @table @kbd
 @item C-M-q
 Reindent all the lines within one parenthetical grouping.
+@item M-q
+Fill a single paragraph in a defun, or reindent all the lines within
+that defun.
 @item C-u @key{TAB}
 Shift an entire parenthetical grouping rigidly sideways so that its
 first line is properly indented.
@@ -429,6 +443,21 @@ indentation of the line where the grouping starts).  The 
function that
 etc.  To correct the overall indentation as well, type @kbd{@key{TAB}}
 first.
 
+@kindex M-q
+@findex prog-fill-reindent-defun
+@vindex beginning-of-defun-function
+@vindex end-of-defun-function
+@vindex fill-paragraph-function
+  To reindent the entire defun around point, type @kbd{M-q}
+(@code{prog-fill-reindent-defun}).  If point is in a comment or a
+string, this command fills and indents the comment or string instead.
+What exactly constitutes a comment, a string, or a defun depends on
+the major mode: the bounds of a defun are decided by the variables
+@code{beginning-of-defun-function} and @code{end-of-defun-function}
+(@pxref{List Motion,,, elisp, The Emacs Lisp Reference Manual}),
+and the filling mechanism is decided by @code{fill-paragraph-function}
+(@pxref{Filling,,, elisp, The Emacs Lisp Reference Manual}).
+
 @kindex C-u TAB
   If you like the relative indentation within a grouping but not the
 indentation of its first line, move point to that first line and type
diff --git a/doc/lispref/ChangeLog.1 b/doc/lispref/ChangeLog.1
index 7c7d49967c..82840aed1d 100644
--- a/doc/lispref/ChangeLog.1
+++ b/doc/lispref/ChangeLog.1
@@ -886,7 +886,7 @@
 2014-03-15  Dmitry Gutov  <dgutov@yandex.ru>
 
        * display.texi (Blinking): Update WRT to the new
-       `blink-matchin-paren' behavior.
+       `blink-matching-paren' behavior.
 
 2014-03-14  Martin Rudalics  <rudalics@gmx.at>
 
diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index 9d929950a7..4111a86aa7 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -1460,19 +1460,10 @@ You can use @dfn{overlays} to alter the appearance of a 
buffer's text on
 the screen, for the sake of presentation features.  An overlay is an
 object that belongs to a particular buffer, and has a specified
 beginning and end.  It also has properties that you can examine and set;
-these affect the display of the text within the overlay.
-
-@cindex scalability of overlays
-@cindex overlays, scalability
-The visual effect of an overlay is the same as of the corresponding
-text property (@pxref{Text Properties}).  However, due to a different
-implementation, overlays generally don't scale well (many operations
-take a time that is proportional to the number of overlays in the
-buffer).  If you need to affect the visual appearance of many portions
-in the buffer, we recommend using text properties.
-
-An overlay uses markers to record its beginning and end; thus,
-editing the text of the buffer adjusts the beginning and end of each
+these affect the display of the text within the overlaid portion of
+the buffer.
+
+Editing the text of the buffer adjusts the beginning and end of each
 overlay so that it stays with the text.  When you create the overlay,
 you can specify whether text inserted at the beginning should be
 inside the overlay or outside, and likewise for the end of the overlay.
@@ -1492,7 +1483,7 @@ inside the overlay or outside, and likewise for the end 
of the overlay.
   This section describes the functions to create, delete and move
 overlays, and to examine their contents.  Overlay changes are not
 recorded in the buffer's undo list, since the overlays are not
-part of the buffer's contents.
+considered part of the buffer's contents.
 
 @defun overlayp object
 This function returns @code{t} if @var{object} is an overlay.
@@ -1514,15 +1505,14 @@ When that happens, the overlay is by default not 
deleted, but you can
 cause it to be deleted by giving it the @samp{evaporate} property
 (@pxref{Overlay Properties, evaporate property}).
 
-The arguments @var{front-advance} and @var{rear-advance} specify the
-marker insertion type for the start of the overlay and for the end of
-the overlay, respectively.  @xref{Marker Insertion Types}.  If they
-are both @code{nil}, the default, then the overlay extends to include
-any text inserted at the beginning, but not text inserted at the end.
-If @var{front-advance} is non-@code{nil}, text inserted at the
-beginning of the overlay is excluded from the overlay.  If
-@var{rear-advance} is non-@code{nil}, text inserted at the end of the
-overlay is included in the overlay.
+The arguments @var{front-advance} and @var{rear-advance} specify what
+happens when text is inserted at the beginning (i.e., before
+@var{start}) and at the end.  If they are both @code{nil}, the
+default, then the overlay extends to include any text inserted at the
+beginning, but not text inserted at the end.  If @var{front-advance}
+is non-@code{nil}, text inserted at the beginning of the overlay is
+excluded from the overlay.  If @var{rear-advance} is non-@code{nil},
+text inserted at the end of the overlay is included in the overlay.
 @end defun
 
 @defun overlay-start overlay
@@ -1541,36 +1531,36 @@ returns @code{nil} if @var{overlay} has been deleted.
 @end defun
 
 @defun delete-overlay overlay
-This function deletes @var{overlay}.  The overlay continues to exist as
-a Lisp object, and its property list is unchanged, but it ceases to be
-attached to the buffer it belonged to, and ceases to have any effect on
-display.
+This function deletes the specified @var{overlay}.  The overlay
+continues to exist as a Lisp object, and its property list is
+unchanged, but it ceases to be attached to the buffer it belonged to,
+and ceases to have any effect on display.
 
 A deleted overlay is not permanently disconnected.  You can give it a
 position in a buffer again by calling @code{move-overlay}.
 @end defun
 
 @defun move-overlay overlay start end &optional buffer
-This function moves @var{overlay} to @var{buffer}, and places its bounds
-at @var{start} and @var{end}.  Both arguments @var{start} and @var{end}
-must specify buffer positions; they may be integers or markers.
+This function moves @var{overlay} to @var{buffer}, and places its
+bounds at @var{start} and @var{end} in that buffer.  Both arguments
+@var{start} and @var{end} must specify buffer positions; they may be
+integers or markers.
 
 If @var{buffer} is omitted, @var{overlay} stays in the same buffer it
-was already associated with; if @var{overlay} was deleted, it goes into
-the current buffer.
+was already associated with; if @var{overlay} was previously deleted
+(and thus isn't associated with any buffer), it goes into the current
+buffer.
 
 The return value is @var{overlay}.
 
-This is the only valid way to change the endpoints of an overlay.  Do
-not try modifying the markers in the overlay by hand, as that fails to
-update other vital data structures and can cause some overlays to be
-lost.
+This function is the only valid way to change the endpoints of an
+overlay.
 @end defun
 
 @defun remove-overlays &optional start end name value
 This function removes all the overlays between @var{start} and
-@var{end} whose property @var{name} has the value @var{value}.  It can
-move the endpoints of the overlays in the region, or split them.
+@var{end} whose property @var{name} has the specified @var{value}.  It
+can move the endpoints of the overlays in the region, or split them.
 
 If @var{name} is omitted or @code{nil}, it means to delete all overlays in
 the specified region.  If @var{start} and/or @var{end} are omitted or
@@ -1581,20 +1571,24 @@ current buffer.
 
 @defun copy-overlay overlay
 This function returns a copy of @var{overlay}.  The copy has the same
-endpoints and properties as @var{overlay}.  However, the marker
+endpoints and properties as @var{overlay}.  However, the text
 insertion type for the start of the overlay and for the end of the
-overlay are set to their default values (@pxref{Marker Insertion
-Types}).
+overlay are set to their default values.
 @end defun
 
   Here are some examples:
 
 @example
+@group
 ;; @r{Create an overlay.}
 (setq foo (make-overlay 1 10))
      @result{} #<overlay from 1 to 10 in display.texi>
+@end group
+@group
 (overlay-start foo)
      @result{} 1
+@end group
+@group
 (overlay-end foo)
      @result{} 10
 (overlay-buffer foo)
@@ -1605,6 +1599,8 @@ Types}).
 ;; @r{Verify the property is present.}
 (overlay-get foo 'happy)
      @result{} t
+@end group
+@group
 ;; @r{Move the overlay.}
 (move-overlay foo 5 20)
      @result{} #<overlay from 5 to 20 in display.texi>
@@ -1612,6 +1608,8 @@ Types}).
      @result{} 5
 (overlay-end foo)
      @result{} 20
+@end group
+@group
 ;; @r{Delete the overlay.}
 (delete-overlay foo)
      @result{} nil
@@ -1625,6 +1623,8 @@ foo
      @result{} nil
 (overlay-buffer foo)
      @result{} nil
+@end group
+@group
 ;; @r{Undelete the overlay.}
 (move-overlay foo 1 20)
      @result{} #<overlay from 1 to 20 in display.texi>
@@ -1635,26 +1635,14 @@ foo
      @result{} 20
 (overlay-buffer foo)
      @result{} #<buffer display.texi>
+@end group
+@group
 ;; @r{Moving and deleting the overlay does not change its properties.}
 (overlay-get foo 'happy)
      @result{} t
+@end group
 @end example
 
-  Emacs stores the overlays of each buffer in two lists, divided
-around an arbitrary center position.  One list extends backwards
-through the buffer from that center position, and the other extends
-forwards from that center position.  The center position can be anywhere
-in the buffer.
-
-@defun overlay-recenter pos
-This function recenters the overlays of the current buffer around
-position @var{pos}.  That makes overlay lookup faster for positions
-near @var{pos}, but slower for positions far away from @var{pos}.
-@end defun
-
-  A loop that scans the buffer forwards, creating overlays, can run
-faster if you do @code{(overlay-recenter (point-max))} first.
-
 @node Overlay Properties
 @subsection Overlay Properties
 @cindex overlay properties
@@ -1711,15 +1699,15 @@ If you want to specify a priority value, use either 
@code{nil}
 (or zero), or a positive integer.  Any other value has undefined behavior.
 
 The priority matters when two or more overlays cover the same
-character and both specify the same property; the one whose
-@code{priority} value is larger overrides the other.  (For the
-@code{face} property, the higher priority overlay's value does not
-completely override the other value; instead, its face attributes
-override the face attributes of the lower priority @code{face}
-property.)  If two overlays have the same priority value, and one is
-nested in the other, then the inner one will prevail over the outer
-one.  If neither is nested in the other then you should not make
-assumptions about which overlay will prevail.
+character and both specify the same property with different values;
+the one whose @code{priority} value is larger overrides the other.
+(For the @code{face} property, the higher priority overlay's value
+does not completely override the other value; instead, its face
+attributes override the face attributes of the @code{face} property
+whose priority is lower.)  If two overlays have the same priority
+value, and one is nested in the other, then the inner one will prevail
+over the outer one.  If neither is nested in the other then you should
+not make assumptions about which overlay will prevail.
 
 Currently, all overlays take priority over text properties.
 
@@ -1780,7 +1768,7 @@ avoided.
 This property is used instead of @code{face} when the mouse is within
 the range of the overlay.  However, Emacs ignores all face attributes
 from this property that alter the text size (e.g., @code{:height},
-@code{:weight}, and @code{:slant}).  Those attributes are always the
+@code{:weight}, and @code{:slant}); those attributes are always the
 same as in the unhighlighted text.
 
 @item display
@@ -1793,9 +1781,8 @@ or shorter, higher or lower, wider or narrower, or 
replaced with an image.
 @item help-echo
 @kindex help-echo @r{(overlay property)}
 If an overlay has a @code{help-echo} property, then when you move the
-mouse onto the text in the overlay, Emacs displays a help string in the
-echo area, or in the tooltip window.  For details see @ref{Text
-help-echo}.
+mouse onto the text in the overlay, Emacs displays a help string in
+the echo area, or as a tooltip.  For details see @ref{Text help-echo}.
 
 @item field
 @kindex field @r{(overlay property)}
@@ -1862,7 +1849,8 @@ The @code{intangible} property on an overlay works just 
like the
 Properties}, for details.
 
 @item isearch-open-invisible
-This property tells incremental search how to make an invisible overlay
+This property tells incremental search (@pxref{Incremental Search,,,
+emacs, The GNU Emacs Manual}) how to make an invisible overlay
 visible, permanently, if the final match overlaps it.  @xref{Invisible
 Text}.
 
@@ -1874,13 +1862,15 @@ visible, temporarily, during the search.  
@xref{Invisible Text}.
 @kindex before-string @r{(overlay property)}
 This property's value is a string to add to the display at the beginning
 of the overlay.  The string does not appear in the buffer in any
-sense---only on the screen.
+sense---only on the screen.  Note that if the text at the beginning of
+the overlay is made invisible, the string will not be displayed.
 
 @item after-string
 @kindex after-string @r{(overlay property)}
 This property's value is a string to add to the display at the end of
 the overlay.  The string does not appear in the buffer in any
-sense---only on the screen.
+sense---only on the screen.  Note that if the text at the end of the
+overlay is made invisible, the string will not be displayed.
 
 @item line-prefix
 This property specifies a display spec to prepend to each
@@ -5467,8 +5457,9 @@ or an image descriptor.
 
   To display something in the margin @emph{in association with}
 certain buffer text, without altering or preventing the display of
-that text, put a @code{before-string} property on the text and put the
-margin display specification on the contents of the before-string.
+that text, put on that text an overlay with a @code{before-string}
+property, and put the margin display specification on the contents of
+the before-string.
 
   Note that if the string to be displayed in the margin doesn't
 specify a face, its face is determined using the same rules and
diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi
index 4b45d89f9d..a767f9c28d 100644
--- a/doc/lispref/files.texi
+++ b/doc/lispref/files.texi
@@ -895,10 +895,14 @@ permissions of the file itself.)
 If the file does not exist, or if there was trouble determining
 whether the file exists, this function returns @code{nil}.
 
-Directories are files, so @code{file-exists-p} can return @code{t} when
-given a directory.  However, because @code{file-exists-p} follows
-symbolic links, it returns @code{t} for a symbolic link
-name only if the target file exists.
+@cindex dangling symlinks, testing for existence
+Directories are files, so @code{file-exists-p} can return @code{t}
+when given a directory.  However, because @code{file-exists-p} follows
+symbolic links, it returns @code{t} for a symbolic link name only if
+the target of the link exists; if your Lisp program needs to consider
+@dfn{dangling symlinks} whose target doesn't exist as existing files,
+use @code{file-attributes} (@pxref{File Attributes}) instead of
+@code{file-exists-p}.
 @end defun
 
 @defun file-readable-p filename
@@ -3205,6 +3209,9 @@ This command creates a directory named @var{dirname}.  If
 @var{parents} is non-@code{nil}, as is always the case in an
 interactive call, that means to create the parent directories first,
 if they don't already exist.
+As a function, @code{make-directory} returns non-@code{nil} if @var{dirname}
+already exists as a directory and @var{parents} is non-@code{nil},
+and returns @code{nil} if it successfully created @var{dirname}.
 @code{mkdir} is an alias for this.
 @end deffn
 
@@ -3378,7 +3385,6 @@ first, before handlers for jobs such as remote file 
access.
 @code{load}, @code{lock-file},
 @code{make-auto-save-file-name},
 @code{make-directory},
-@code{make-directory-internal},
 @code{make-lock-file-name},
 @code{make-nearby-temp-file},
 @code{make-process},
@@ -3440,7 +3446,6 @@ first, before handlers for jobs such as remote file 
access.
 @code{load}, @code{lock-file},
 @code{make-auto-save-file-name},
 @code{make-direc@discretionary{}{}{}tory},
-@code{make-direc@discretionary{}{}{}tory-internal},
 @code{make-lock-file-name},
 @code{make-nearby-temp-file},
 @code{make-process},
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index c4e724d761..3174056ed8 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -2423,19 +2423,6 @@ Buffers}), and avoids slowing down internal or temporary 
buffers, such
 as those created by @code{with-temp-buffer} (@pxref{Definition of
 with-temp-buffer,, Current Buffer}).
 
-@item overlay_center
-This field holds the current overlay center position.  @xref{Managing
-Overlays}.
-
-@item overlays_before
-@itemx overlays_after
-These fields hold, respectively, a list of overlays that end at or
-before the current overlay center, and a list of overlays that end
-after the current overlay center.  @xref{Managing Overlays}.
-@code{overlays_before} is sorted in order of decreasing end position,
-and @code{overlays_after} is sorted in order of increasing beginning
-position.
-
 @item name
 A Lisp string that names the buffer.  It is guaranteed to be unique.
 @xref{Buffer Names}.  This and the following fields have their names
@@ -2562,6 +2549,9 @@ buffer-local (@pxref{Buffer-Local Variables}), whose 
corresponding
 variable names have underscores replaced with dashes.  For instance,
 @code{mode_line_format} stores the value of @code{mode-line-format}.
 
+@item overlays
+The inveral tree containing this buffer's overlays.
+
 @item last_selected_window
 This is the last window that was selected with this buffer in it, or @code{nil}
 if that window no longer displays this buffer.
diff --git a/doc/lispref/keymaps.texi b/doc/lispref/keymaps.texi
index 1e4bf4eb86..5882f24794 100644
--- a/doc/lispref/keymaps.texi
+++ b/doc/lispref/keymaps.texi
@@ -841,7 +841,7 @@ keymaps:
           (@var{find-in-any} emulation-mode-map-alists)
           (@var{find-in-any} minor-mode-overriding-map-alist)
           (@var{find-in-any} minor-mode-map-alist)
-          (if (get-text-property (point) 'local-map)
+          (if (get-char-property (point) 'local-map)
               (@var{find-in} (get-char-property (point) 'local-map))
             (@var{find-in} (current-local-map)))))
     (@var{find-in} (current-global-map)))
diff --git a/doc/lispref/modes.texi b/doc/lispref/modes.texi
index c472f9b441..c44938f392 100644
--- a/doc/lispref/modes.texi
+++ b/doc/lispref/modes.texi
@@ -4967,12 +4967,22 @@ first child where parent is @code{argument_list}, use
 (match nil "argument_list" nil nil 0 0)
 @end example
 
+@item n-p-gp
+Short for ``node-parent-grandparent'', this matcher is a function of 3
+arguments: @var{node-type}, @var{parent-type}, and
+@var{grandparent-type}.  It returns a function that is called with 3
+arguments: @var{node}, @var{parent}, and @var{bol}, and returns
+non-@code{nil} if: (1) @var{node-type} matches @var{node}'s type, and
+(2) @var{parent-type} matches @var{parent}'s type, and (3)
+@var{grandparent-type} matches @var{parent}'s parent's type.  If any
+of @var{node-type}, @var{parent-type}, and @var{grandparent-type} is
+@code{nil}, this function doesn't check for it.
+
 @item comment-end
 This matcher is a function that is called with 3 arguments:
 @var{node}, @var{parent}, and @var{bol}, and returns non-@code{nil} if
 point is before a comment ending token.  Comment ending tokens are
-defined by regular expression @code{treesit-comment-end}
-(@pxref{Tree-sitter major modes, treesit-comment-end}).
+defined by regular expression @code{comment-end-skip}
 
 @item first-sibling
 This anchor is a function that is called with 3 arguments: @var{node},
@@ -5009,19 +5019,11 @@ This is useful as the beginning of the buffer is always 
at column 0.
 
 @item comment-start
 This anchor is a function that is called with 3 arguments: @var{node},
-@var{parent}, and @var{bol}, and returns the position right after the
+@var{parent}, and @var{bol}, and returns the position after the
 comment-start token.  Comment-start tokens are defined by regular
-expression @code{treesit-comment-start} (@pxref{Tree-sitter major
-modes, treesit-comment-start}).  This function assumes @var{parent} is
-the comment node.
+expression @code{comment-start-skip}.  This function assumes
+@var{parent} is the comment node.
 
-@item coment-start-skip
-This anchor is a function that is called with 3 arguments: @var{node},
-@var{parent}, and @var{bol}, and returns the position after the
-comment-start token and any whitespace characters following that
-token.  Comment-start tokens are defined by regular expression
-@code{treesit-comment-start}.  This function assumes @var{parent} is
-the comment node.
 @end ftable
 @end defvar
 
diff --git a/doc/lispref/package.texi b/doc/lispref/package.texi
index a503a7edde..4cb0c3214a 100644
--- a/doc/lispref/package.texi
+++ b/doc/lispref/package.texi
@@ -152,9 +152,9 @@ the various headers, as illustrated by the following 
example:
 
 @example
 @group
-;;; superfrobnicator.el --- Frobnicate and bifurcate flanges
+;;; superfrobnicator.el --- Frobnicate and bifurcate flanges  -*- 
lexical-binding:t -*-
 
-;; Copyright (C) 2011 Free Software Foundation, Inc.
+;; Copyright (C) 2022 Free Software Foundation, Inc.
 @end group
 
 ;; Author: J. R. Hacker <jrh@@example.com>
diff --git a/doc/lispref/parsing.texi b/doc/lispref/parsing.texi
index 3223875320..adb4c5e6e0 100644
--- a/doc/lispref/parsing.texi
+++ b/doc/lispref/parsing.texi
@@ -409,6 +409,13 @@ Create a parser for the specified @var{buffer} and 
@var{language}
 By default, this function reuses a parser if one already exists for
 @var{language} in @var{buffer}, but if @var{no-reuse} is
 non-@code{nil}, this function always creates a new parser.
+
+If that buffer is an indirect buffer, its base buffer is used instead.
+That is, indirect buffers use their base buffer's parsers.  If the
+base buffer is narrowed, an indirect buffer might not be able to
+retrieve information of the portion of the buffer text that are
+invisible in the base buffer.  Lisp programs should widen as necessary
+should they want to use a parser in an indirect buffer.
 @end defun
 
 Given a parser, we can query information about it.
@@ -447,7 +454,8 @@ tree incrementally.
 @defun treesit-parser-list &optional buffer
 This function returns the parser list of @var{buffer}.  If
 @var{buffer} is @code{nil} or omitted, it defaults to the current
-buffer.
+buffer.  If that buffer is an indirect buffer, its base buffer is used
+instead.  That is, indirect buffers use their base buffer's parsers.
 @end defun
 
 @defun treesit-parser-delete parser
@@ -1727,20 +1735,6 @@ For more information of these built-in tree-sitter 
features,
 For supporting mixing of multiple languages in a major mode,
 @pxref{Multiple Languages}.
 
-Setting the following local variables allows tree-sitter's indentation
-engine to correctly indent multi-line comments:
-
-@defvar treesit-comment-start
-This should be a regular expression matching an opening comment token.
-For example, it should match @samp{//}, @samp{////}, @samp{/*},
-@samp{/****}, etc., in C.
-@end defvar
-
-@defvar treesit-comment-end
-This should be a regular expression matching a closing comment token.
-For example, it should match @samp{*/}, @samp{****/}, etc., in C.
-@end defvar
-
 @node Tree-sitter C API
 @section Tree-sitter C API Correspondence
 
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index bc5a4cf24a..58f2703c8b 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -719,7 +719,7 @@ calling @var{function} on the elements in @var{sequence}.
 then with that result and the third element of @var{sequence}, etc.
 @var{function} should be a function of two arguments.
 
-@var{function} is called with two arguments.  @var{intial-value}
+@var{function} is called with two arguments.  @var{initial-value}
 (and then the accumulated value) is used as the first argument, and
 the elements in @var{sequence} are used for the second argument.
 
diff --git a/doc/lispref/variables.texi b/doc/lispref/variables.texi
index 7206f2acd2..12dd58c85b 100644
--- a/doc/lispref/variables.texi
+++ b/doc/lispref/variables.texi
@@ -188,15 +188,18 @@ It determines the value returned by evaluating the 
variable symbol,
 and it is the binding acted on by @code{setq}.
 
   For most purposes, you can think of the current binding as the
-innermost local binding, or the global binding if there is no
-local binding.  To be more precise, a rule called the @dfn{scoping
-rule} determines where in a program a local binding takes effect.  The
+innermost local binding, or the global binding if there is no local
+binding.  To be more precise, a rule called the @dfn{scoping rule}
+determines where in a program a local binding takes effect.  The
 default scoping rule in Emacs Lisp is called @dfn{dynamic scoping},
 which simply states that the current binding at any given point in the
 execution of a program is the most recently-created binding for that
 variable that still exists.  For details about dynamic scoping, and an
 alternative scoping rule called @dfn{lexical scoping}, @pxref{Variable
-Scoping}.
+Scoping}.  Lately Emacs is moving towards using lexical binding in
+more and more places, with the goal of eventually making lexical
+binding the default.  In particular, all Emacs Lisp source files and
+the @file{*scratch*} buffer use lexical scoping.
 
   The special forms @code{let} and @code{let*} exist to create local
 bindings:
@@ -266,6 +269,17 @@ Compare the following example with the example above for 
@code{let}.
      @result{} (1 1)
 @end group
 @end example
+
+@noindent
+Basically, the @code{let*} binding of @code{x} and @code{y} in the
+previous example is equivalent to using nested @code{let} bindings:
+
+@example
+(let ((y 1))
+  (let ((z y))
+    (list y z)))
+@end example
+
 @end defspec
 
 @defspec letrec (bindings@dots{}) forms@dots{}
@@ -843,9 +857,10 @@ error is signaled.
 
 @defmac setopt [symbol form]@dots{}
 This is like @code{setq} (see above), but meant for user options.
-This macro uses the Customize machinery to set the variable(s).  In
-particular, @code{setopt} will run the setter function associated with
-the variable.  For instance, if you have:
+This macro uses the Customize machinery to set the variable(s)
+(@pxref{Variable Definitions}).  In particular, @code{setopt} will run
+the setter function associated with the variable.  For instance, if
+you have:
 
 @example
 @group
@@ -870,6 +885,12 @@ will also issue a message:
 option.  For instance, using @code{setopt} to set a user option
 defined with a @code{number} type to a string will signal an error.
 
+Unlike @code{defcustom} and related customization commands, such as
+@code{customize-variable}, @code{setopt} is meant for non-interactive
+use, in particular in the user init file.  For that reason, it doesn't
+record the standard, saved, and user-set values, and doesn't mark the
+variable as candidate for saving in the custom file.
+
 The @code{setopt} macro can be used on regular, non-user option
 variables, but is much less efficient than @code{setq}.  The main use
 case for this macro is setting user options in the user's init file.
@@ -974,6 +995,11 @@ binding can also be accessed from the Lisp debugger.}.  It 
also has
 binding can live on even after the binding construct has finished
 executing, by means of special objects called @dfn{closures}.
 
+  The dynamic binding was (and still is) the default in Emacs for many
+years, but lately Emacs is moving towards using lexical binding in
+more and more places, with the goal of eventually making that the
+default.
+
   The following subsections describe dynamic binding and lexical
 binding in greater detail, and how to enable lexical binding in Emacs
 Lisp programs.
diff --git a/doc/man/etags.1 b/doc/man/etags.1
index 8dbea25c4c..d3d58b8212 100644
--- a/doc/man/etags.1
+++ b/doc/man/etags.1
@@ -209,7 +209,7 @@ otherwise.  This is particularly useful when storing many 
predefined
 regexps in a file.
 .br
 In its second form, \fIregexfile\fP is the name of a file that contains
-a number of arguments to the \fI\-\-regex\=\fP option,
+a number of arguments to the \fI\-\-regex=\fP option,
 one per line.  Lines beginning with a space or tab are assumed
 to be comments, and ignored.
 
@@ -220,22 +220,22 @@ from shell interpretation.
 
 Tag the DEFVAR macros in the emacs source files:
 .br
-\fI\-\-regex\='/[ \\t]*DEFVAR_[A-Z_ \\t(]+"\\([^"]+\\)"/'\fP
+\fI\-\-regex='/[ \\t]*DEFVAR_[A-Z_ \\t(]+"\\([^"]+\\)"/'\fP
 .\"" This comment is to avoid confusion to Emacs syntax highlighting
 .br
 
 Tag VHDL files (this example is a single long line, broken here for
 formatting reasons):
 .br
-\fI\-\-language\=none\ \-\-regex='/[\ \\t]*\\(ARCHITECTURE\\|\\
-CONFIGURATION\\)\ +[^\ ]*\ +OF/'\ \-\-regex\='/[\ \\t]*\\
+\fI\-\-language=none\ \-\-regex='/[\ \\t]*\\(ARCHITECTURE\\|\\
+CONFIGURATION\\)\ +[^\ ]*\ +OF/'\ \-\-regex='/[\ \\t]*\\
 \\(ATTRIBUTE\\|ENTITY\\|FUNCTION\\|PACKAGE\\(\ BODY\\)?\\
 \\|PROCEDURE\\|PROCESS\\|TYPE\\)[\ \\t]+\\([^\ \\t(]+\\)/\\3/'\fP
 .br
 
 Tag Tcl files (this last example shows the usage of a \fItagregexp\fP):
 .br
-\fI\-\-lang\=none \-\-regex\='/proc[\ \\t]+\\([^\ \\t]+\\)/\\1/'\fP
+\fI\-\-lang=none \-\-regex='/proc[\ \\t]+\\([^\ \\t]+\\)/\\1/'\fP
 
 .br
 A regexp can be preceded by {\fIlang\fP}, thus restricting it to match
diff --git a/doc/misc/Makefile.in b/doc/misc/Makefile.in
index a7dbbbb48f..60b14172c3 100644
--- a/doc/misc/Makefile.in
+++ b/doc/misc/Makefile.in
@@ -67,14 +67,14 @@ MAKEINFO_OPTS = --force -I$(emacsdir)
 DOCMISC_W32 = @DOCMISC_W32@
 
 ## Info files to build and install on all platforms.
-INFO_COMMON = auth autotype bovine calc ccmode cl \
-       dbus dired-x ebrowse ede ediff edt efaq eglot eieio \
-       emacs-gnutls emacs-mime epa erc ert eshell eudc eww \
-       flymake forms gnus htmlfontify idlwave ido info.info \
-       mairix-el message mh-e modus-themes newsticker nxml-mode \
-       octave-mode org pcl-cvs pgg rcirc reftex remember sasl \
-       sc semantic ses sieve smtpmail speedbar srecode todo-mode \
-       tramp transient url vhdl-mode vip viper vtable widget wisent woman
+INFO_COMMON = auth autotype bovine calc ccmode cl dbus dired-x         \
+       ebrowse ede ediff edt efaq eglot eieio emacs-gnutls             \
+       emacs-mime epa erc ert eshell eudc eww flymake forms gnus       \
+       htmlfontify idlwave ido info.info mairix-el message mh-e        \
+       modus-themes newsticker nxml-mode octave-mode org pcl-cvs pgg   \
+       rcirc reftex remember sasl sc semantic ses sieve smtpmail       \
+       speedbar srecode todo-mode tramp transient url use-package      \
+       vhdl-mode vip viper vtable widget wisent woman
 
 ## Info files to install on current platform.
 INFO_INSTALL = $(INFO_COMMON) $(DOCMISC_W32)
@@ -186,7 +186,8 @@ $(foreach ifile,$(filter-out 
info.info,$(INFO_TARGETS)),$(eval $(call info_templ
 ## Extra dependencies.
 
 ## FIXME Updating this list manually is unreliable.
-need_emacsver = calc cl dired-x efaq efaq-w32 erc forms ido newsticker reftex 
remember woman
+need_emacsver = calc cl dired-x efaq efaq-w32 erc forms ido    \
+       newsticker reftex remember use-package woman
 need_emacsver_prefix = $(addprefix ${buildinfodir}/,${need_emacsver})
 
 $(need_emacsver_prefix:=.info) $(need_emacsver:=.dvi) $(need_emacsver:=.pdf) 
$(need_emacsver:=.html) : ${emacsdir}/emacsver.texi
diff --git a/doc/misc/eglot.texi b/doc/misc/eglot.texi
index b76f8bdfd7..2aff038b9a 100644
--- a/doc/misc/eglot.texi
+++ b/doc/misc/eglot.texi
@@ -955,6 +955,13 @@ Note that you can still configure the excluded Emacs 
features manually
 to use Eglot in your @code{eglot-managed-mode-hook} or via some other
 mechanism.
 
+@vindex eglot-report-progress
+@cindex progress
+@item eglot-report-progress
+Set this variable to true if you'd like progress notifications coming
+from the LSP server to be handled as Emacs's progress reporting
+facilities.
+
 @vindex eglot-workspace-configuration
 @cindex server workspace configuration
 @item eglot-workspace-configuration
diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi
index 5ad739a77e..2ab2e90894 100644
--- a/doc/misc/erc.texi
+++ b/doc/misc/erc.texi
@@ -570,10 +570,20 @@ toggle never mutates @code{erc-modules}.
 
 @menu
 * Connecting::                  Ways of connecting to an IRC server.
-* SASL::                        Authenticating via SASL
+* SASL::                        Authenticating via SASL.
 * Sample Configuration::        An example configuration file.
 * Integrations::                Integrations available for ERC.
 * Options::                     Options that are available for ERC.
+
+@detailmenu
+--- Detailed Node Listing ---
+
+Integrations
+
+* URL::                         Opening IRC URLs in ERC.
+* auth-source::                 Retrieving auth-source entries with ERC.
+
+@end detailmenu
 @end menu
 
 @node Connecting
@@ -643,7 +653,7 @@ while helpers, like @code{erc-compute-nick}, will determine 
other
 parameters, and some, like @code{client-certificate}, will just be
 @code{nil}.
 
-@anchor{ERC client-certificate}
+@anchor{client-certificate}
 To use a certificate with @code{erc-tls}, specify the optional
 @var{client-certificate} keyword argument, whose value should be as
 described in the documentation of @code{open-network-stream}: if
@@ -687,6 +697,8 @@ machine irc.libera.chat key /home/bandali/my-cert.key cert 
/home/bandali/my-cert
 
 @xref{Help for users,,,auth, Emacs auth-source Library}, for more on the
 @file{.authinfo}/@file{.netrc} backend of @code{auth-source}.
+For other uses of auth-source throughout ERC, @pxref{auth-source,
+ERC's auth-source integration}.
 @end defun
 
 @subheading Server
@@ -778,9 +790,9 @@ ERC should automatically attempt to connect with another 
nickname.
 You can manually set another nickname with the /NICK command.
 @end defopt
 
-@anchor{ERC username}
+@anchor{username parameter}
 @subheading User
-@cindex user
+@cindex username parameter
 
 @defun erc-compute-user &optional user
 Determine a suitable value to send as the first argument of the
@@ -803,8 +815,27 @@ A permanent username value to send for all connections.  
It should be
 a string abiding by the rules of the network.
 @end defopt
 
+@anchor{password parameter}
+@anchor{server password}
+@cindex password, server
 @subheading Password
-@cindex password
+
+This parameter was traditionally meant to specify a @dfn{server
+password} to be sent along with the IRC @samp{PASS} command.  However,
+such passwords aren't widely used.  Instead, networks typically expect
+them, when present, to convey other authentication information.  In
+the case of account-services (a.k.a., ``NickServ'') credentials, this
+typically involves a special syntax, such as @samp{myuser:mypass}.
+IRC bouncers often do something similar but include a pre-configured
+network-ID component, for example, @samp{bncuser/mynet:bncpass}.
+
+In general, if you have @emph{not} been asked by your network or
+bouncer to specify a repurposed server password, you should instead
+consider setting up @samp{services} or, preferably, @samp{sasl}, both
+ERC modules (@pxref{Modules}).  In addition to performing
+network-account authentication, these obviate the need for this
+parameter completely, although both can optionally borrow it for their
+own purposes.  (@xref{SASL, SASL in ERC}.)
 
 @defopt erc-prompt-for-password
 If non-@code{nil} (the default), @kbd{M-x erc} and @kbd{M-x erc-tls}
@@ -814,109 +845,9 @@ invocations of @code{erc} and @code{erc-tls}.
 
 @noindent
 If you prefer, you can set this option to @code{nil} and use the
-@code{auth-source} mechanism to store your password.  For instance, if
-the option @code{auth-sources} contains @file{~/.authinfo}, put
-something like the following in that file:
-
-@example
-machine irc.example.net login mynick password sEcReT
-@end example
-
-@noindent
-For server passwords, that is, passwords sent for the IRC @samp{PASS}
-command, the @samp{host} field (@w{@code{machine irc.example.net}} in
-the above example)
-corresponds to the @var{server} parameter used by @code{erc} and
-@code{erc-tls}.  Unfortunately, specifying a network, like
-@samp{Libera.Chat}, or a specific network server, like
-@samp{platinum.libera.chat}, won't normally work for looking up a server
-password because such information isn't available during opening
-introductions.  (Actually, ERC @emph{can} find entries with arbitrary
-@samp{host} values for any context, including server passwords, but
-that requires customizing the more advanced options below.)
-
-If ERC can't find a suitable server password, it will just skip the IRC
-@samp{PASS} command altogether, something users may want when using
-CertFP or engaging NickServ via ERC's ``services'' module.  If that is
-what you'd like to do, you can also customize the option
-@code{erc-auth-source-server-function} to @code{nil} to skip
-server-password lookup for all servers.  Note that some networks and
-IRCds may accept account-services authentication via server password
-using the nonstandard @samp{mynick:sEcReT} convention.
-
-As just mentioned, you can also use @code{auth-source} to authenticate
-to account services the traditional way, through a bot called
-@samp{NickServ}.  To tell ERC to do that, set
-@code{erc-use-auth-source-for-nickserv-password} to @code{t}.  For
-these and most other queries, entries featuring custom identifiers and
-networks are matched first, followed by network-specific servers and
-dialed endpoints (typically, the @var{server} argument passed to
-@code{erc}). The following netrc-style entries appear in order of
-precedence:
-
-@example
-machine Libera/cellphone login MyNick password sEcReT
-machine Libera.Chat login MyNick password sEcReT
-machine zirconium.libera.chat login MyNick password sEcReT
-machine irc.libera.chat login MyNick password sEcReT
-@end example
-
-@noindent
-Remember that field labels vary per backend, so @samp{machine} (in
-netrc's case) maps to auth-source's generalized notion of a host,
-hence the @samp{:host} keyword property.  Also, be sure to mind the
-syntax of your chosen backend medium.  For example, always quote
-channel names in a netrc file.
-
-If this all seems overly nuanced or just plain doesn't appeal to you,
-see options @code{erc-auth-source-services-function} and friends, described
-below.  These let you query auth-source your way.  Most users can
-simply ignore the passed-in arguments and get by with something like
-the following:
-
-@lisp
-(defun my-fancy-auth-source-func (&rest _)
-  (let* ((host (read-string "host: " nil nil "default"))
-         (pass (auth-source-pick-first-password :host host)))
-    (if (and pass (string-search "libera" host))
-        (concat "MyNick:" pass)
-      pass)))
-@end lisp
-
-Lastly, ERC also consults @code{auth-source} to find ``keys'' that may
-be required by certain channels you join.  When modifying a
-traditional @code{auth-source} entry for this purpose, put the channel
-name in the @samp{user} field (for example, @samp{login "#fsf"}, in
-netrc's case).  The actual key goes in the @samp{password} (or
-@samp{secret}) field.
-
-@noindent
-For details, @pxref{Top,,auth-source, auth, Emacs auth-source Library}.
-
-@anchor{ERC auth-source functions}
-@defopt erc-auth-source-server-function
-@end defopt
-@defopt erc-auth-source-services-function
-@end defopt
-@defopt erc-auth-source-join-function
-
-ERC calls these functions with keyword arguments recognized by
-@code{auth-source-search}, namely, those deemed most relevant to the
-current context, if any.  For example, with NickServ queries,
-@code{:user} is the ``desired'' nickname rather than the current one.
-Generalized names, like @code{:user} and @code{:host}, are always used
-over back-end specific ones, like @code{:login} or @code{:machine}.
-ERC expects a string to use as the secret or @code{nil}, if the search
-fails.
-
-@findex erc-auth-source-search
-The default value for all three options is the function
-@code{erc-auth-source-search}.  It tries to merge relevant contextual
-parameters with those provided or discovered from the logical connection
-or the underlying transport.  Some auth-source back ends may not be
-compatible; netrc, plstore, json, secrets, and pass are currently
-supported.
-@end defopt
+auth-source facility to retrieve a server password, although hitting
+@kbd{RET} at the prompt may achieve the same effect.
+@xref{auth-source, ERC's auth-source integration}, for more.
 
 @subheading Full name
 
@@ -946,8 +877,8 @@ This can be either a string or a function to call.
 @end defopt
 
 
-@subheading ID
 @anchor{Network Identifier}
+@subheading ID
 
 ERC uses an abstract designation, called @dfn{network context
 identifier}, for referring to a connection internally.  While normally
@@ -1002,7 +933,7 @@ first is lowercase without delims (@samp{deadbeef}) and 
the second
 uppercase with colon seps (@samp{DE:AD:BE:EF}).  These days, there's
 usually a @samp{CERT ADD} command offered by NickServ that can
 register you automatically if you issue it while connected with a
-client cert.  (@pxref{ERC client-certificate}).
+client cert.  @xref{client-certificate}.
 
 Additional considerations:
 @enumerate
@@ -1038,30 +969,32 @@ ERC> /msg NickServ set property \
 This should be your network account username, typically the same one
 registered with nickname services.  Specify this when your NickServ
 login differs from the @code{:user} you're connecting with.
-(@pxref{ERC username})
+@xref{username parameter}.
 @end defopt
 
 @defopt erc-sasl-password
-As noted elsewhere, the @code{:password} parameter for @code{erc-tls}
-was originally intended for traditional ``server passwords,'' but these
-aren't really used any more.  As such, this option defaults to
-borrowing that parameter for its own uses, thus allowing you to call
-@code{erc-tls} with @code{:password} set to your NickServ password.
+As noted elsewhere, the entry-point @code{:password} param was
+originally intended for traditional ``server passwords,'' but these
+aren't really used any more (@pxref{password parameter}).  As such,
+this option defaults to borrowing that parameter for its own uses,
+thus allowing you to call @code{erc-tls} with @code{:password} set to
+your NickServ password.
 
 You can also set this to a nonemtpy string, and ERC will send that
 when needed, no questions asked.  Or, if you'd rather use auth-source,
 set @code{erc-sasl-auth-source-function} to a function, and ERC will
-perform an auth-source query instead.  As last resort in all cases,
-ERC will prompt you for input.
+perform an auth-source query instead.  In all cases, ERC will prompt
+you for input as a last resort.
 
 Lastly, if your mechanism is @code{ecdsa-nist256p-challenge}, this
 option should instead hold the file name of your key.
 @end defopt
 
+@anchor{SASL auth-source function}
 @defopt erc-sasl-auth-source-function
 This is nearly identical to the other ERC @samp{auth-source} function
-options (@pxref{ERC auth-source functions}) except that the default
-value here is @code{nil}, meaning you have to set it to something like
+options (@pxref{auth-source functions}) except that the default value
+here is @code{nil}, meaning you have to set it to something like
 @code{erc-auth-source-search} for queries to be performed.  For
 convenience, this module provides the following as a possible value:
 
@@ -1163,9 +1096,9 @@ both networks.
 
 @subheading Troubleshooting
 
-@strong{Warning:} ERC's SASL offering is currently limited by a lack
-of support for proper IRCv3 capability negotiation.  In most cases,
-this shouldn't affect your ability to authenticate.
+First and foremost, please know that ERC's SASL offering is currently
+limited by a lack of support for proper IRCv3 capability negotiation.
+In most cases, this shouldn't affect your ability to authenticate.
 
 If you're struggling, remember that your SASL password is almost
 always your NickServ password.  When in doubt, try restoring all SASL
@@ -1260,12 +1193,19 @@ stuff, to the current ERC buffer."
 @section Integrations
 @cindex integrations
 
-@subheading URL
+@menu
+* auth-source::                 Retrieving auth-source entries with ERC.
+@end menu
+
+@anchor{URL}
+@subsection URL
+@cindex URL
+
 For anything to work, you'll want to set @code{url-irc-function} to
 @code{url-irc-erc}.  As a rule of thumb, libraries relying directly on
 @code{url-retrieve} should be fine out the box from Emacs 29.1 onward.
 On older versions of Emacs, you may need to @code{(require 'erc)}
-beforehand. @pxref{Retrieving URLs,,, url, URL}.
+beforehand.  @xref{Retrieving URLs,,, url, URL}.
 
 For other apps and libraries, such as those relying on the
 higher-level @code{browse-url}, you'll oftentimes be asked to specify
@@ -1282,6 +1222,160 @@ need a function as well:
 @noindent
 Users on Emacs 28 and below may need to use @code{browse-url} instead.
 
+@node auth-source
+@subsection auth-source
+@cindex auth-source
+
+You can configure ERC to use the built-in auth-source library for
+looking up passwords. @xref{Top,,auth-source, auth, Emacs auth-source
+Library}, for general info on setting up various backends, but keep in
+mind that some of these may not be compatible.  Those currently
+supported are netrc, plstore, json, secrets, and pass.  To get started
+with the default backend, netrc, put a line like the following in your
+@file{~/.authinfo.gpg} (or any file named in the option
+@code{auth-sources}):
+
+@example
+machine irc.example.net login mynick password sEcReT
+@end example
+
+@subsubheading Server Passwords
+When retrieving passwords to accompany the IRC @samp{PASS} command
+(@pxref{password parameter}), ERC asks auth-source to match the
+@var{server} parameter of @code{erc-tls} against each entry's
+@samp{host} field (@w{@code{machine irc.example.net}} in the above
+example).  Unfortunately, specifying a network, like
+@samp{Libera.Chat}, or a specific network server, like
+@samp{platinum.libera.chat}, won't normally work for looking up a
+server password because that information isn't available during
+opening introductions.  (Actually, ERC @emph{can} find entries with
+arbitrary @samp{host} values for any context, including server
+passwords, but that requires customizing the more advanced options
+below.)
+
+If ERC can't find a suitable server password, it will just skip the
+IRC @samp{PASS} command altogether, something users may want when
+using CertFP or engaging NickServ via ERC's @code{services} module.
+If that appeals to you, consider customizing the option
+@code{erc-auth-source-server-function} to @code{nil} to skip
+server-password lookup for all servers.  Note that some networks and
+IRCds may accept account-services authentication via server password.
+Also, some ERC modules may commandeer the @code{erc-tls}
+@var{password} parameter for their own ends, which likely don't
+involve a server password.
+
+@subsubheading The @samp{services} module
+You can use auth-source to authenticate to account services the
+traditional way through a bot called @samp{NickServ}.  To do so, add
+@code{services} to @code{erc-modules} and set the option
+@code{erc-use-auth-source-for-nickserv-password} to @code{t}.  After
+that, expect the @samp{user} parameter in relevant auth-source queries
+to be your current nickname.
+
+Most of the time, a query's precise contextual details (such as
+whether a nick was granted or forcibly assigned) shouldn't affect how
+you define entries in your backend.  However, if something isn't quite
+working, you may want to investigate the interplay between the option
+@code{erc-nickserv-identify-mode} and account services.  In
+particular, if you find yourself facing nicks suffixed with an
+@code{erc-nick-uniquifier} (the infamous @samp{`}), check that the
+network's entry in @code{erc-nickserv-alist} is up to date, and do let
+us know if something's off (@pxref{Getting Help and Reporting Bugs}).
+Of course, if you've had your fill of fiddling with this module,
+consider switching to SASL for what's likely a more consistent
+auth-source experience.  (@xref{SASL}.)
+
+@subsubheading Default query behavior
+When preparing entries for your backend, it may help to get a feel for
+how ERC and its modules conduct searches, especially when exploring a
+new context, such as channel keys.  (Hint: in such situations, try
+temporarily setting the variable @code{auth-source-debug} to @code{t}
+and checking @samp{*Messages*} periodically for insights into how
+auth-source is operating.)  Overall, though, ERC tries to be
+consistent in performing queries across various authentication
+contexts.  Here's what to expect with respect to the @samp{host}
+field, which, by default, most heavily influences the fate of a query:
+
+@enumerate
+@item
+entries featuring custom identifiers and networks are matched first
+(@pxref{Network Identifier})
+@item
+followed by network-specific servers
+@item
+and, finally, dialed endpoints (typically the @var{server} argument
+passed to @code{erc-tls})
+@end enumerate
+
+@noindent
+The following netrc-style entries appear in order of precedence:
+
+@example
+machine Libera/cellphone login MyNick password sEcReT
+machine Libera.Chat login MyNick password sEcReT
+machine zirconium.libera.chat login MyNick password sEcReT
+machine irc.libera.chat login MyNick password sEcReT
+@end example
+
+@noindent
+Remember that field labels vary per backend, so @samp{machine} (in
+netrc's case) maps to auth-source's generalized notion of a host,
+hence the @samp{:host} keyword parameter to @code{auth-source-search}.
+Also, be sure to mind the syntax of your chosen backend medium.  For
+example, always quote channel names in a netrc file.
+
+Lastly, if this all seems overly nuanced or just plain doesn't appeal
+to you, please see options @code{erc-auth-source-services-function}
+and friends, described just below.
+
+@subsubheading Custom query functions
+These let you query auth-source your way.  Most users can
+simply ignore the passed-in arguments and get by with something like
+the following:
+
+@lisp
+(defun my-fancy-auth-source-func (&rest _)
+  (let* ((host (read-string "host: " nil nil "default"))
+         (pass (auth-source-pick-first-password :host host)))
+    (if (and pass (string-search "libera" host))
+        (concat "MyNick:" pass)
+      pass)))
+@end lisp
+
+@anchor{auth-source functions}
+@defopt erc-auth-source-server-function
+@end defopt
+@defopt erc-auth-source-services-function
+@end defopt
+@defopt erc-auth-source-join-function
+
+ERC calls these functions with keyword arguments recognized by
+@code{auth-source-search}, namely, those deemed most relevant to the
+current context, if any.  For example, when identifying to services,
+@code{:user} contains your current nickname.  Generalized parameter
+names, like @code{:user} and @code{:host}, are always preferred over
+backend specific ones, like @code{:login} or @code{:machine}.  In
+return, ERC expects a string if the search succeeds or @code{nil} if
+it fails.
+
+@findex erc-auth-source-search
+The default value for all three options is the function
+@code{erc-auth-source-search}.  It tries to merge relevant contextual
+parameters with those provided or discovered from the logical
+connection or the underlying transport.
+
+For using auth-source along with SASL, @pxref{SASL auth-source
+function}.
+@end defopt
+
+@subsubheading Channel keys
+ERC also consults @code{auth-source} to find ``keys'' that may be
+required by certain channels you join.  When modifying a traditional
+@code{auth-source} entry for this purpose, put the channel name in the
+@samp{user} field (for example, @samp{login "#fsf"}, in netrc's case).
+The actual key goes in the @samp{password} (or @samp{secret}) field.
+
+
 @node Options
 @section Options
 @cindex options
diff --git a/doc/misc/eshell.texi b/doc/misc/eshell.texi
index e6ddcf11df..f9796d69a9 100644
--- a/doc/misc/eshell.texi
+++ b/doc/misc/eshell.texi
@@ -256,12 +256,40 @@ as an argument will ``spread'' the elements into multiple 
arguments:
 @end example
 
 @subsection Quoting and escaping
-As with other shells, you can escape special characters and spaces
-with by prefixing the character with a backslash (@code{\}), or by
-surrounding the string with apostrophes (@code{''}) or double quotes
-(@code{""}).  This is needed especially for file names with special
-characters like pipe (@code{|}), which could be part of remote file
-names.
+As with other shells, you can escape special characters and spaces by
+prefixing the character with a backslash (@samp{\}), or by surrounding
+the string with apostrophes (@samp{''}) or double quotes (@samp{""}).
+This is needed especially for file names with special characters like
+pipe (@samp{|}), which could be part of remote file names.
+
+When you escape a character with @samp{\} outside of any quotes, the
+result is the literal character immediately following it.  For
+example, @code{\$10} means the literal string @code{$10}.
+
+Inside of double quotes, most characters have no special meaning.
+However, @samp{\}, @samp{"}, and @samp{$} are still special; to escape
+them, use backslash as above.  Thus, if the value of the variable
+@var{answer} is @code{42}, then @code{"The answer is: \"$answer\""}
+returns the string @code{The answer is: "42"}.  However, when escaping
+characters with no special meaning, the result is the full
+@code{\@var{c}} sequence.  For example, @code{"foo\bar"} means the
+literal string @code{foo\bar}.
+
+Additionally, when escaping a newline, the whole escape sequence is
+removed by the parser.  This lets you continue commands across
+multiple lines:
+
+@example
+~ $ echo "foo\
+bar"
+foobar
+@end example
+
+Inside apostrophes, escaping works differently.  All characters
+between the apostrophes have their literal meaning except @samp{'},
+which ends the quoted string.  To insert a literal apostrophe, you can
+use @samp{''}, so @code{'It''s me'} means the literal string
+@code{It's me}.
 
 When using expansions (@pxref{Expansion}) in an Eshell command, the
 result may potentially be of any data type.  To ensure that the result
@@ -321,9 +349,9 @@ alias (@pxref{Aliases}).  Example:
 @example
 ~ $ which sudo
 eshell/sudo is a compiled Lisp function in `em-tramp.el'.
-~ $ alias sudo '*sudo $*'
+~ $ alias sudo '*sudo $@@*'
 ~ $ which sudo
-sudo is an alias, defined as "*sudo $*"
+sudo is an alias, defined as "*sudo $@@*"
 @end example
 
 @vindex eshell-prefer-lisp-functions
@@ -447,7 +475,7 @@ Manual}.
 
 If @code{eshell-plain-diff-behavior} is non-@code{nil}, then this
 command does not use Emacs's internal @code{diff}.  This is the same
-as using @samp{alias diff '*diff $*'}.
+as using @samp{alias diff '*diff $@@*'}.
 
 @item dirname
 @cmindex dirname
@@ -517,9 +545,9 @@ but use Emacs's internal @code{grep} instead.
 
 If @code{eshell-plain-grep-behavior} is non-@code{nil}, then these
 commands do not use Emacs's internal @code{grep}.  This is the same as
-using @samp{alias grep '*grep $*'}, though this setting applies to all
-of the built-in commands for which you would need to create a separate
-alias.
+using @samp{alias grep '*grep $@@*'}, though this setting applies to
+all of the built-in commands for which you would need to create a
+separate alias.
 
 @item history
 @cmindex history
@@ -575,7 +603,7 @@ Alias to Emacs's @code{locate} function, which simply runs 
the external
 
 If @code{eshell-plain-locate-behavior} is non-@code{nil}, then Emacs's
 internal @code{locate} is not used.  This is the same as using
-@samp{alias locate '*locate $*'}.
+@samp{alias locate '*locate $@@*'}.
 
 @item ls
 @cmindex ls
@@ -999,24 +1027,47 @@ necessary.  Its value is 
@code{@var{emacs-version},eshell}.
 @node Aliases
 @section Aliases
 
-@vindex $*
+@findex eshell-read-aliases-list
 Aliases are commands that expand to a longer input line.  For example,
-@command{ll} is a common alias for @code{ls -l}, and would be defined
-with the command invocation @kbd{alias ll 'ls -l $*'}; with this defined,
-running @samp{ll foo} in Eshell will actually run @samp{ls -l foo}.
-Aliases defined (or deleted) by the @command{alias} command are
-automatically written to the file named by @code{eshell-aliases-file},
-which you can also edit directly (although you will have to manually
-reload it).
-
-@vindex $1, $2, @dots{}
+@command{ll} is a common alias for @code{ls -l}.  To define this alias
+in Eshell, you can use the command invocation @kbd{alias ll 'ls -l
+$@@*'}; with this defined, running @samp{ll foo} in Eshell will
+actually run @samp{ls -l foo}.  Aliases defined (or deleted) by the
+@command{alias} command are automatically written to the file named by
+@code{eshell-aliases-file}, which you can also edit directly.  After
+doing so, use @w{@kbd{M-x eshell-read-aliases-list}} to load the
+edited aliases.
+
 Note that unlike aliases in Bash, arguments must be handled
-explicitly.  Typically the alias definition would end in @samp{$*} to
-pass all arguments along.  More selective use of arguments via
-@samp{$1}, @samp{$2}, etc., is also possible.  For example,
+explicitly.  Within aliases, you can use the special variables
+@samp{$*}, @samp{$0}, @samp{$1}, @samp{$2}, etc. to refer to the
+arguments passed to the alias.
+
+@table @code
+
+@vindex $*
+@item $*
+This expands to the list of arguments passed to the alias.  For
+example, if you run @code{my-alias 1 2 3}, then @samp{$*} would be the
+list @code{(1 2 3)}.  Note that since this variable is a list, using
+@samp{$*} in an alias will pass this list as a single argument to the
+aliased command.  Therefore, when defining an alias, you should
+usually use @samp{$@@*} to pass all arguments along, splicing them
+into your argument list (@pxref{Dollars Expansion}).
+
+@vindex $0
+@item $0
+This expands to the name of the alias currently being executed.
+
+@vindex $1, $2, @dots{}, $9
+@item $1, $2, @dots{}, $9
+These variables expand to the nth argument (starting at 1) passed to
+the alias.  This lets you selectively use an alias's arguments, so
 @kbd{alias mcd 'mkdir $1 && cd $1'} would cause @kbd{mcd foo} to
 create and switch to a directory called @samp{foo}.
 
+@end table
+
 @node History
 @section History
 @cmindex history
@@ -1278,12 +1329,36 @@ to split the string.  @var{regexp} can be any form 
other than a
 number.  For example, @samp{$@var{var}[: 0]} will return the first
 element of a colon-delimited string.
 
+@cindex length operator, in variable expansion
 @item $#@var{expr}
-Expands to the length of the result of @var{expr}, an expression in
-one of the above forms.  For example, @samp{$#@var{var}} returns the
-length of the variable @var{var} and @samp{$#@var{var}[0]} returns the
-length of the first element of @var{var}.  Again, signals an error if
-the result of @var{expr} is not a string or a sequence.
+This is the @dfn{length operator}.  It expands to the length of the
+result of @var{expr}, an expression in one of the above forms.  For
+example, @samp{$#@var{var}} returns the length of the variable
+@var{var} and @samp{$#@var{var}[0]} returns the length of the first
+element of @var{var}.  Again, signals an error if the result of
+@var{expr} is not a string or a sequence.
+
+@cindex splice operator, in variable expansion
+@item $@@@var{expr}
+This is the @dfn{splice operator}.  It ``splices'' the elements of
+@var{expr} (an expression of one of the above forms) into the
+resulting list of arguments, much like the @samp{,@@} marker in Emacs
+Lisp (@pxref{Backquote, , , elisp, The Emacs Lisp Reference Manual}).
+The elements of @var{expr} become arguments at the same level as the
+other arguments around it.  For example, if @var{numbers} is the list
+@code{(1 2 3)}, then:
+
+@example
+@group
+~ $ echo 0 $numbers
+(0
+ (1 2 3))
+@end group
+@group
+~ $ echo 0 $@@numbers
+(0 1 2 3)
+@end group
+@end example
 
 @end table
 
@@ -2002,7 +2077,7 @@ Allow for a Bash-compatible syntax, such as:
 
 @example
 alias arg=blah
-function arg () @{ blah $* @}
+function arg () @{ blah $@@* @}
 @end example
 
 @item Pcomplete sometimes gets stuck
diff --git a/doc/misc/eww.texi b/doc/misc/eww.texi
index 1060cd805a..7b32f04aa8 100644
--- a/doc/misc/eww.texi
+++ b/doc/misc/eww.texi
@@ -67,9 +67,15 @@ Indices
 
 @node Overview
 @chapter Overview
-@dfn{EWW}, the Emacs Web Wowser, is a web browser for GNU Emacs.  It
-can load, parse, and display various web pages using @dfn{shr.el}.
-However, a GNU Emacs with @code{libxml2} support is required.
+
+@dfn{EWW}, the Emacs Web Wowser, is a web browser for GNU Emacs that
+provides a simple, no-frills experience that focuses on readability.
+It loads, parses, and displays web pages using @dfn{shr.el}.  It can
+display images inline, if Emacs was built with image support, but
+there is no support for CSS or JavaScript.
+
+To use EWW, you need to use an Emacs built with @code{libxml2}
+support.
 
 @node Basics
 @chapter Basic Usage
diff --git a/doc/misc/flymake.texi b/doc/misc/flymake.texi
index 4561b760c0..80e1bceb8e 100644
--- a/doc/misc/flymake.texi
+++ b/doc/misc/flymake.texi
@@ -847,7 +847,7 @@ Binding,,, elisp, The Emacs Lisp Reference Manual}) to be 
active.
 @findex flymake-proc-legacy-flymake
 The backend @code{flymake-proc-legacy-flymake} was originally designed
 to be extended for supporting new syntax check tools and error message
-patterns.  It is also controlled by its own set of customization variables
+patterns.  It is also controlled by its own set of customization variables.
 
 @node Proc customization variables
 @section Customization variables for the Proc backend
diff --git a/doc/misc/org.org b/doc/misc/org.org
index 43d85099cf..c6b8e73fd1 100644
--- a/doc/misc/org.org
+++ b/doc/misc/org.org
@@ -1401,7 +1401,7 @@ you, configure the option ~org-table-auto-blank-field~.
 - {{{kbd(M-x org-table-blank-field)}}} ::
 
   #+findex: org-table-blank-field
-  Blank the field at point.
+  Blank the current table field or active region.
 
 - {{{kbd(S-TAB)}}} (~org-table-previous-field~) ::
 
@@ -20021,11 +20021,16 @@ changes.
   | =nofnadjust= | Do not renumber and sort automatically.                |
 
   #+vindex: org-hide-block-startup
-  To hide blocks on startup, use these keywords.  The
-  corresponding variable is ~org-hide-block-startup~.
+  #+vindex: org-hide-drawer-startup
+  To hide blocks or drawers on startup, use these keywords.  The
+  corresponding variables are ~org-hide-block-startup~ and
+  ~org-hide-drawer-startup~.
+
+  | =hideblocks=    | Hide all begin/end blocks on startup. |
+  | =nohideblocks=  | Do not hide blocks on startup.        |
+  | =hidedrawers=   | Hide all begin/end blocks on startup. |
+  | =nohidedrawers= | Do not hide blocks on startup.        |
 
-  | =hideblocks=   | Hide all begin/end blocks on startup. |
-  | =nohideblocks= | Do not hide blocks on startup.        |
 
   #+vindex: org-pretty-entities
   The display of entities as UTF-8 characters is governed by the
diff --git a/doc/misc/rcirc.texi b/doc/misc/rcirc.texi
index 84933a9ca7..37d62c7c41 100644
--- a/doc/misc/rcirc.texi
+++ b/doc/misc/rcirc.texi
@@ -691,11 +691,11 @@ window is showing them), the mode line will now show you 
the abbreviated
 channel or nick name.  Use @kbd{C-c C-@key{SPC}} to switch to these
 buffers.
 
-@cindex rcirc-track-abbrevate-flag
+@cindex rcirc-track-abbreviate-flag
 By default the channel names are abbreviated, set
-@code{rcirc-track-abbrevate-flag} to a non-@code{nil} value. This might be
-interesting if the IRC activities are not tracked in the mode line,
-but somewhere else.
+@code{rcirc-track-abbreviate-flag} to a non-@code{nil} value.  This
+might be interesting if the IRC activities are not tracked in the mode
+line, but somewhere else.
 
 @vindex rcirc-mode-hook
 If you prefer not to load @code{rcirc} immediately, you can delay the
diff --git a/doc/misc/use-package.texi b/doc/misc/use-package.texi
new file mode 100644
index 0000000000..c587d23d74
--- /dev/null
+++ b/doc/misc/use-package.texi
@@ -0,0 +1,2163 @@
+\input texinfo    @c -*- texinfo -*-
+@c %**start of header
+@setfilename ../../info/use-package.info
+@settitle use-package User Manual
+@set USEP_VER 2.4.5
+@set USEP_DIST as distributed with Emacs @value{EMACSVER}
+@include docstyle.texi
+@syncodeindex vr cp
+@syncodeindex fn cp
+@include emacsver.texi
+@c %**end of header
+
+@copying
+This manual is for use-package @value{USEP_VER} @value{USEP_DIST}.
+
+Copyright @copyright{} 2022 Free Software Foundation, Inc.
+
+@quotation
+Permission is granted to copy, distribute and/or modify this document
+under the terms of the GNU Free Documentation License, Version 1.3 or
+any later version published by the Free Software Foundation; with no
+Invariant Sections, with the Front-Cover Texts being ``A GNU Manual'',
+and with the Back-Cover Texts as in (a) below.  A copy of the license
+is included in the section entitled ``GNU Free Documentation License''.
+
+(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and
+modify this GNU manual.''
+@end quotation
+@end copying
+
+@dircategory Emacs misc features
+@direntry
+* use-package: (use-package). Declarative package configuration for Emacs.
+@end direntry
+
+@finalout
+@titlepage
+@title use-package User Manual
+@subtitle for version USEP_VER
+@author John Wiegley & Stefan Kangas
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+
+@contents
+
+@ifnottex
+@node Top
+@top use-package User Manual
+
+The @code{use-package} macro allows you to set up package
+customization in your init file in a declarative way.  It takes care
+of many things for you that would otherwise require a lot of
+repetitive boilerplate code.  It can help with common customization,
+such as binding keys, setting up hooks, customizing user options and
+faces, autoloading, and more.  It also helps you keep Emacs startup
+fast, even when you use many (even hundreds) of packages.
+
+Note that use-package is not a package manager.  Although use-package
+does have the useful capability to interface with the Emacs package
+manager, its primary purpose is help with the configuration and
+loading of packages, not with managing their download, upgrades, and
+installation.
+
+@insertcopying
+
+@menu
+* Basic Concepts::              Basic concepts of use-package.
+* Getting Started::             A gentle introduction to use-package.
+* Loading Packages::            How and when packages are loaded.
+* Configuring Packages::        Package configuration keywords.
+* Installing packages::         Ensuring packages are available.
+* Byte-compiling::              Byte-compiling your init file.
+* Troubleshooting::             What to do when there's trouble.
+
+Appendices
+* Keyword extensions::          Adding new use-package keywords.
+* History::                     History and acknowledgments.
+* GNU Free Documentation License::  The license for this manual.
+
+Index
+* Index::
+@end menu
+@end ifnottex
+
+@c ----------------------------------------------------------------------------
+@node Basic Concepts
+@chapter Basic Concepts
+
+use-package provides the @code{use-package} macro, that simplifies the
+customization and use of packages in Emacs.  It was created for a few
+basic reasons, each of which drove the design.  Understanding these
+reasons may help make some of those decisions clearer:
+
+@cindex reasons for developing use-package
+@enumerate
+@item
+Allow gathering all the configuration details of a package into one
+place, making it easier to copy, disable, or move it elsewhere in the
+init file.
+
+@item
+Reduce duplication and repetitive boilerplate, capturing several
+common practices as mere keywords both easy and intuitive to use.
+
+@item
+Make startup time of Emacs as short as possible, without sacrificing
+the quantity of add-on packages used.
+
+@item
+Ensure that errors encountered during startup disable only the
+package(s) raising the error(s), and as little else as possible,
+leaving Emacs as close to fully functional as possible.
+
+@item
+Allow byte-compiling your init file, so that any warnings or errors
+you see at startup are meaningful.  In this way, even if
+byte-compilation is not used for speed (see item 3 above), it can
+still be used as a sanity check.
+@end enumerate
+
+It is worth noting that use-package is not intended to replace the
+standard customization command @w{@kbd{M-x customize}} (@pxref{Easy
+Customization,,, emacs, GNU Emacs Manual}).  On the contrary, it is
+designed to work together with it, for things that Customize cannot
+do.
+
+@c ----------------------------------------------------------------------------
+@node Getting Started
+@chapter Getting Started
+@cindex quick-start instructions
+
+This chapter provides instructions and examples for quickly getting
+started with use-package.  The first thing you need to do is make sure
+that @file{use-package} itself is loaded.  To do that, put this at the
+top of your init file:
+
+@lisp
+(require 'use-package)
+@end lisp
+
+@cindex declaration
+The above makes the @code{use-macro} available for us in the rest of
+your init file.  In this manual, we say that each call to
+@code{use-macro} is a @dfn{declaration}, to highlight the declarative
+nature of its syntax.
+
+To unconditionally load a package named @samp{foo}, add the following
+declaration to your init file:
+
+@lisp
+(use-package foo)
+@end lisp
+
+@noindent
+This declaration is equivalent to using @code{require} (@pxref{Named
+Features,,, elisp, GNU Emacs Lisp Reference Manual}), with some
+use-package specific error handling added in.  Just like
+@code{require}, it needs the package @samp{foo} to be installed and
+available via your @code{load-path} (@pxref{Installing packages}).
+
+To evaluate some Lisp @emph{before} the @samp{foo} package is loaded,
+use the @code{:init} keyword:
+
+@lisp
+@group
+(use-package foo
+  :init
+  (setq foo-variable t))
+@end group
+@end lisp
+
+Similarly, @code{:config} can be used to execute code @emph{after} a
+package is loaded.  In cases where loading is done lazily
+(@pxref{Loading Packages}), this execution is deferred until after the
+loading actually occurs.  As you might expect, you can use
+@code{:init} and @code{:config} together:
+
+@lisp
+@group
+(use-package foo
+  :init
+  (setq foo-variable t)
+  :config
+  (foo-mode 1))
+@end group
+@end lisp
+
+The above declarations will load the @samp{foo} package
+immediately.  In most cases, this is not necessary or desirable, as
+that will slow down Emacs startup.  Instead, you should try to set
+things up so that packages are only loaded when they are actually
+needed (a.k.a. ``autoloading'').  If you have installed a package from
+@acronym{GNU} @acronym{ELPA} that provides it's own autoloads, it is often
+enough to say:
+
+@lisp
+@group
+(use-package foo
+  :defer t)
+@end group
+@end lisp
+
+@noindent
+This will avoid loading the package.  Now, when you run any autoloaded
+command, the package @samp{foo} is loaded automatically.  (Which
+commands from a package are marked to auto-load by default is the
+decision of the package authors.)
+
+In some cases, you might need or want to provide your own autoloads.
+The more complex example below autoloads the commands
+@code{isearch-moccur} and @code{isearch-all} from the package
+@file{color-moccur.el}, and binds keys both globally and in
+@code{isearch-mode-map}.  When one of these two commands are used, the
+package will be loaded.  At that point, @code{moccur-edit} is also loaded,
+to allow editing of the @code{moccur} buffer.
+
+@lisp
+@group
+(use-package color-moccur
+  :commands (isearch-moccur isearch-all)
+  :bind (("M-s O" . moccur)
+         :map isearch-mode-map
+         ("M-o" . isearch-moccur)
+         ("M-O" . isearch-moccur-all))
+  :init
+  (setq isearch-lazy-highlight t)
+  :config
+  (use-package moccur-edit))
+@end group
+@end lisp
+
+Some packages will suggest ready-made @code{use-package} declarations
+that you can use.  Where possible, it is a good idea to copy them, and
+use that as a starting point.
+
+That should be enough to get you started!
+
+@c ----------------------------------------------------------------------------
+@node Loading Packages
+@chapter Loading Packages
+@cindex loading packages with use-package
+
+Before use-package can load an Emacs Lisp package, it must be
+available in a directory on your @code{load-path}.  When you install
+packages using the built-in @code{install-package} command, it will do
+this automatically for you.  Packages shipped with Emacs (built-in
+packages) are always available.
+
+Some packages have more than one library.  In those cases, you might
+need more than one @code{use-package} declaration to make sure the
+package is properly loaded.  For complex configurations, you might
+also need more than one declaration for a package with the same name.
+
+use-package can interface with @samp{package.el} to install packages
+on Emacs start.  @xref{Installing packages}, for details.
+
+@menu
+* Loading basics::              How and when packages are loaded.
+* Deferring loading::           Loading packages later.
+* Forcing loading::             Loading packages immediately.
+* Conditional loading::         Loading packages conditionally.
+* Loading sequentially::        Loading packages in sequence.
+* Load dependencies::           Don't load without dependencies.
+* Manual installation::         Loading manually installed packages.
+@end menu
+
+@node Loading basics
+@section How and when use-package loads packages
+
+The call to the @code{use-package} macro will load a package either
+immediately, or when the package is first used (via autoloading).  In the
+simplest case, a @code{use-package} declaration loads a package when
+it is evaluated.@footnote{This happens both at run-time and at
+compile-time.  @xref{Byte-compiling}.}  If the declaration is in your
+init file, this happens automatically each time Emacs is started.
+
+For example, the declaration below immediately loads the library
+@code{foo}, just like @code{require} would:
+
+@lisp
+(use-package foo)
+@end lisp
+
+@noindent
+If the library @samp{foo} is not available in your @code{load-path},
+the declaration logs a warning to the @samp{*Messages*} buffer.
+
+@cindex package vs library
+@c So, confusingly, (use-package foo) actually means to use the
+@c _library_ foo.el, not all of the _package_ foo's libraries?
+@c Should this be explicitly explained here?
+Note that a ``package'' is different from an Emacs Lisp ``library''.
+The above declaration tells use-package to load the @emph{library}
+@file{foo.el}, which in the overwhelming majority of cases also
+resides in a @emph{package} named @code{foo}.  But the package
+@code{foo} might also contain a library named @file{foo-extra.el}.  If
+that library is not loaded automatically, you will need a separate
+@code{use-package} declaration to make sure that it is loaded when
+needed.  This manual will often use the terms ``package'' and
+``library'' interchangeably, as this distinction does not usually
+matter, but you should keep it in mind for the cases when it does.
+
+The details of how and when you should load a package might differ
+from one package to another.  When in doubt, refer to the package
+documentation for details.
+
+@node Deferring loading
+@section Deferring package loading
+@cindex deferring loading of package
+
+@cindex autoloading packages
+@cindex loading lazily
+@cindex lazy loading of packages
+In the examples we have seen so far, use-package loads packages every
+time you start Emacs, even if that package is never used.  That will
+make starting Emacs slower.  use-package therefore allows setting
+things up in such a way that packages are only loaded when some of the
+package's commands is first used (either with @kbd{M-x} or via some key
+binding).  This is based on autoloading, a full description of which
+is outside the scope of this manual.  @xref{Autoload,,, elisp, GNU
+Emacs Lisp Reference Manual}, for the full story.
+
+@cindex triggers, for loading packages
+Some @code{use-package} keywords provide autoload @dfn{triggers} that
+cause a package to be loaded when certain events occur.  For example,
+the @code{:hook} keyword sets up a trigger that fires when the
+specified hook is run, and then loads the package automatically.  The
+other trigger keywords, all of which are described later in this
+manual, are @code{:commands}, @code{:bind}, @code{:bind*},
+@code{:bind-keymap}, @code{:bind-keymap*}, @code{:mode}, and
+@code{:interpreter}.
+
+@subheading The @code{:defer} keyword
+
+@findex :defer
+If you did not specify any autoloading keyword, use-package will fall
+back to loading the package immediately (typically when Emacs is
+starting up).  This can be overridden using the @code{:defer} keyword.
+It takes one boolean argument: a non-@code{nil} value means to stop
+this package from being immediately loaded.  Here is an example of
+using @code{:defer} to postpone loading the package @samp{foo}:
+
+@lisp
+@group
+(use-package foo
+  :defer t)
+@end group
+@end lisp
+
+Using @code{:defer t} by itself like this is rarely useful.
+Typically, you would only use it together with a keyword like
+@code{:config} (@pxref{Lisp Configuration}), or @code{:ensure}
+(@pxref{Installing packages}).
+
+@subheading Defer loading until idle for N seconds
+
+@findex :defer@r{, with a numeric argument}
+You can also give a numeric argument @var{n} to @w{@code{:defer}} to
+specify that a package should be loaded (if it hasn't already) after
+Emacs has been idle for @var{n} seconds.  For example, use the
+following to make use-package load @samp{foo} after 30 seconds of idle
+time:
+
+@lisp
+@group
+(use-package foo
+  :defer 30)
+@end group
+@end lisp
+
+@subheading When to use @code{:defer}
+
+When using autoloading keywords, there is no need to also use
+@code{:defer}.  It doesn't hurt to add it in this case, perhaps for
+extra clarity, but it is redundant.
+
+You should use @code{:defer} to force deferred loading, in cases when
+use-package isn't creating any autoloads for you.  For example, you
+might know that some other package will already do something to cause
+your package to load at the appropriate time.  This is usually the
+case when you install a package using @code{package-install}, as
+packages installed in this way normally always have their own
+autoloads already set up.
+
+@subheading Making @w{@code{:defer t}} the default
+
+@cindex defer loading by default
+@cindex lazy loading by default
+@vindex use-package-always-defer
+If you customize the user option @code{use-package-always-defer} to
+non-@code{nil}, the @code{use-package} macro will behave as if
+@w{@code{:defer t}} is always specified.  This can be overridden for
+individual declarations using either @w{@code{:defer nil}} or
+@w{@code{:demand t}} (@pxref{Forcing loading}).
+
+@node Forcing loading
+@section Forcing package to load immediately
+@cindex forcing immediate loading
+
+@findex :demand
+The presence of autoloading trigger keywords can be overridden using
+@code{:demand t}, which forces the package to load immediately.  Thus,
+even if you use an autoloading keyword such as @code{:bind}
+(@pxref{Key bindings}), adding @code{:demand} will force loading to
+occur immediately.  It will also avoid creating an autoload for the
+bound key, as it would be redundant.
+
+If you specify both @w{@code{:demand t}} and @w{@code{:defer t}}, the
+@code{:defer} keyword will take precedence.
+
+@node Conditional loading
+@section Loading packages conditionally
+@cindex conditional loading
+@cindex loading conditions
+
+@findex :if
+@findex :when
+@findex :unless
+The @code{:if}, @code{:when}, and @code{:unless} keywords predicates
+the loading and initialization of packages.  They all accept one
+argument, an Emacs Lisp form that is evaluated at run-time.
+
+If the argument of the @code{:if} keyword evaluates to non-@code{nil},
+the package will be loaded and initialized.  The @code{:when} keyword
+is provided as an alias for @code{:if}.  Finally, the @code{:unless}
+keyword is the inverse of @code{:if}, such that @w{@code{:unless foo}}
+means the same thing as @w{@code{:if (not foo)}}.
+
+For example, if you only want to load @samp{foo} in graphical Emacs
+sessions, you could use the following:
+
+@lisp
+@group
+(use-package foo
+  :if (display-graphic-p))
+@end group
+@end lisp
+
+@subheading Some common use cases
+
+Here are some common cases for conditional loading, and how to achieve
+them.
+
+@c FIXME: Too many redundant examples?  E.g., why do we need both an
+@c example for system-type and window-system? or both of the last 2
+@c examples?
+@itemize
+
+@item
+Operating system
+
+The following example loads a package only on GNU/Linux.  See the
+docstring of @code{system-type} for other valid values.
+
+@lisp
+:if (eq system-type 'gnu/linux)
+@end lisp
+
+@item
+Window system
+
+The example below loads a package only on macOS and X.  See the
+docstring of @code{window-system} for valid values.
+
+@lisp
+:if (memq window-system '(ns x))
+@end lisp
+
+@item
+Installed package
+
+The following example loads a package only when the @samp{foo} package
+is installed.
+
+@lisp
+:if (package-installed-p 'foo)
+@end lisp
+
+@item
+Libraries in @code{load-path}
+
+The example below loads a package only when @file{foo.el} is available
+in your @code{load-path} (for example, if you installed that file
+manually):
+
+@lisp
+:if (locate-library "foo.el")
+@end lisp
+@end itemize
+
+@subheading Making conditional loading affect @code{:preface} and 
@code{:ensure}
+
+@cindex conditional loading before @code{:preface} or @code{:ensure}
+If you need to make a use-package form conditional so that the condition
+occurs before even @code{:ensure} (@pxref{Install package}) or
+@code{:preface} (@pxref{Preface keyword}), use @code{when}
+around the @code{use-package} form itself.  For example:
+
+@lisp
+@group
+(when (memq window-system '(mac ns))
+  (use-package foo
+    :ensure t))
+@end group
+@end lisp
+
+@node Loading sequentially
+@section Loading packages in sequence
+@cindex loading a package after other packages
+
+@findex :after
+Sometimes it only makes sense to configure a package after another one
+has been loaded, because certain variables or functions are not in
+scope until that time.  This can be achieved with the @code{:after}
+keyword, which allows a fairly rich description of the exact
+conditions when loading should occur.  The @code{:after} keyword takes
+as argument either a symbol indicating the package name, a list of
+such symbols, or a list of selectors (see below).
+
+Here is an example of using the @acronym{GNU} @acronym{ELPA} packages
+@file{hydra}, @file{ivy}, and @file{ivy-hydra}.  Note that
+@file{ivy-hydra} will always be loaded last:
+
+@lisp
+(use-package hydra)
+
+(use-package ivy)
+
+@group
+(use-package ivy-hydra
+  :after (ivy hydra))
+@end group
+@end lisp
+
+In this case, because the declarations are evaluated in the order they
+occur, the use of @code{:after} is not strictly necessary.  However,
+if @samp{hydra} and @samp{ivy} were to be autoloaded, using
+@code{:after} guarantees that @samp{ivy-hydra} is not loaded until it
+is actually needed.  By using @code{:after}, the above code will also
+work even if the order of the declaration changes.  This means that
+moving things around in your init file is less likely to break things.
+
+@subheading Using @code{:after} selectors
+
+@findex :all@r{, (with @code{:after})}
+@findex :any@r{, (with @code{:after})}
+@cindex list of selectors, for @code{:after}
+The @code{:after} keyword also accepts a list of selectors.  By
+default, @w{@code{:after (foo bar)}} is the same as @w{@code{:after
+(:all foo bar)}}, meaning that loading of the given package will not happen
+until both @code{foo} and @code{bar} have been loaded.  Here are some
+of the other possibilities:
+
+@verbatim
+:after (foo bar)
+:after (:all foo bar)
+:after (:any foo bar)
+:after (:all (:any foo bar) (:any baz quux))
+:after (:any (:all foo bar) (:all baz quux))
+@end verbatim
+
+When you nest selectors, such as in @w{@code{(:any (:all foo bar)
+(:all baz quux))}}, it means that the package will be loaded when
+either both @code{foo} and @code{bar} have been loaded, or when both
+@code{baz} and @code{quux} have been loaded.
+
+@cindex @code{use-package-always-defer}, with @code{:after}
+Pay attention when setting @code{use-package-always-defer} to a
+non-@code{nil} value, and also using the @code{:after} keyword.  In
+that case, you will need to specify how the declared package is to be
+loaded: for example, by some @code{:bind} (@pxref{Global
+keybindings}).  If you are not using one of the keywords that
+registers autoloads, such as @code{:bind} or @code{:hook}
+(@pxref{Hooks}), and your package manager does not provide autoloads,
+it is possible that your package will never be loaded if you do not
+add @code{:demand t} to those declarations.
+
+@node Load dependencies
+@section Prevent loading if dependencies are missing
+@cindex prevent loading package if dependencies are missing
+
+@findex :requires
+While the @code{:after} keyword delays loading until the dependencies
+are loaded, the somewhat simpler @code{:requires} keyword @emph{never}
+loads the package if the dependencies are not available when the
+@code{use-package} declaration is evaluated.  In this context,
+``available'' means that @code{foo} is available if @w{@code{(featurep
+'foo)}} evaluates to a non-@code{nil} value.  For example:
+
+@lisp
+@group
+(use-package abbrev
+  :requires foo)
+@end group
+@end lisp
+
+@noindent
+This is the same as:
+
+@lisp
+@group
+(use-package abbrev
+  :if (featurep 'foo))
+@end group
+@end lisp
+
+As a convenience, a list of such packages may be specified:
+
+@lisp
+@group
+(use-package abbrev
+  :requires (foo bar baz))
+@end group
+@end lisp
+
+For more complex logic, such as that supported by @code{:after},
+simply use @code{:if} and the appropriate Lisp expression.
+
+@node Manual installation
+@section Manually installed package
+
+When installing packages manually, without Emacs' built-in package
+manager (@file{package.el}), it will obviously not help you set up
+autoloads or add it to your @code{load-path}.  You must do it
+yourself.  However, use-package makes this more convenient.
+
+@menu
+* Load path::                   Using a custom @code{load-path}.
+* Manual autoloads::            Setting up autoloads manually.
+@end menu
+
+@node Load path
+@subsection Setting a custom @code{load-path}
+@cindex custom @code{load-path} for loading a package
+@cindex @code{load-path}, add directories for loading a package
+
+When installing packages manually, you must make sure its libraries
+are available on your @code{load-path}.  @xref{Lisp Libraries,,,
+emacs, GNU Emacs Manual}, for more details about package loading.
+
+@findex :load-path
+The @code{:load-path} keyword provides a convenient way to add
+directories to your load path.  It takes as argument a symbol, a
+function, a string or a list of strings.  If a directory is specified
+as a relative file name, it is expanded relative to
+@code{user-emacs-directory}.
+
+For example:
+
+@lisp
+@group
+(use-package org
+  :load-path "site-lisp/org/lisp/"
+  :commands org-mode)
+@end group
+@end lisp
+
+When using a symbol or a function to provide a dynamically generated
+list of directories, you must inform the byte-compiler of this
+definition, so that the value is available at byte-compilation time.
+This is done by using the special form @code{eval-and-compile} (as
+opposed to @code{eval-when-compile}, @pxref{Eval During Compile,,,
+elisp, GNU Emacs Lisp Reference Manual}).  Furthermore, this value is
+fixed to the value it had during compilation.  If the operation is
+costly, you do not have to repeat it again on each startup.  For
+example:
+
+@lisp
+@group
+(eval-and-compile
+  (defun ess-site-load-path ()
+    (shell-command-to-string "find ~ -path ess/lisp")))
+@end group
+
+@group
+(use-package ess-site
+  :load-path (lambda () (list (ess-site-load-path)))
+  :commands R)
+@end group
+@end lisp
+
+@node Manual autoloads
+@subsection Setting up autoloads manually
+
+Packages often document how to set up its autoloads when it is being
+manually installed.  If it does, follow those instructions.
+Otherwise, you might want to set them up manually.
+
+@cindex autoloads for packages, setting up manually
+@cindex package autoloads, setting up manually
+
+@findex :commands
+@findex :autoload
+To autoload an interactive command, use the @code{:commands} keyword,
+which takes either a symbol or a list of symbols as its argument.  It
+creates autoloads for those commands (which defers loading of the
+module until those commands are used).
+
+The @code{:autoload} keyword takes the same arguments as
+@code{:commands}, but is used to autoload non-interactive functions.
+Here is an example:
+
+@lisp
+@group
+(use-package org-crypt
+  :autoload org-crypt-use-before-save-magic)
+@end group
+@end lisp
+
+@c ----------------------------------------------------------------------------
+@node Configuring Packages
+@chapter Configuring Packages
+@cindex configure packages using @code{use-package}
+@cindex customize package configuration
+
+This chapter describes the various keywords provided by
+@code{use-package} that help you configure packages.
+
+@menu
+* Lisp Configuration::          Using Lisp to configure packages.
+* Key bindings::                Making your own keybindings.
+* Hooks::                       Adding functions to hooks.
+* Modes and interpreters::      Enabling modes automatically.
+* Magic handlers::              Using regexps to enable modes.
+* User options::                Setting user options.
+* Faces::                       Customizing faces.
+* Hiding minor modes::          Tidying up the mode line.
+@end menu
+
+@node Lisp Configuration
+@section Using Lisp code for configuring packages
+@cindex configure package using Lisp forms
+
+The most general way to add customizations are the @code{:preface},
+@code{:init}, and @code{:config} keywords.  They all accept one or
+more Emacs Lisp forms, up to the next keyword, that are evaluated in
+order.  This lets you add arbitrary Lisp code to your
+@code{use-package} declarations.
+
+The only difference between these keywords is when they are evaluated.
+
+@menu
+* Preface keyword::             Evaluate code before anything else.
+* Init keyword::                Evaluate code before loading package.
+* Config keyword::              Evaluate code after loading package.
+* Best practices::              When to use @code{:config}, @code{:init}, and 
@code{:preface}.
+@end menu
+
+@node Preface keyword
+@subsection @code{:preface} is evaluated first
+
+@findex :preface
+The @code{:preface} section is evaluated before anything else, except
+@code{:disabled} and @code{:ensure}.  It can be used to establish
+function and variable definitions that will:
+
+@enumerate
+@item
+Make the byte-compiler happy: it will not complain about functions
+whose definitions are unknown.
+
+@item
+Define functions and variables that will be used in an @code{:if}
+test.
+@end enumerate
+
+Note that whatever is specified within @code{:preface} is evaluated
+both at load time and at byte-compilation time, in order to ensure
+that definitions are seen by both the Lisp evaluator and the
+byte-compiler.  Therefore, you should avoid having any side-effects in
+your @code{:preface} forms, and restrict them to symbol declarations
+and definitions.
+
+@node Init keyword
+@subsection @code{:init} is evaluated before loading package
+
+@findex :init
+The @code{:init} section is evaluated just before the package is
+loaded.  Note that the @code{:init} form is run unconditionally --
+even if the package happens to not exist on your system.  You must
+therefore remember to restrict @code{:init} code to what would succeed
+either way; put the rest in the @code{:config} section.  @code{:init}
+also always happens before package load, whether @code{:config} has
+been deferred or not.
+
+@node Config keyword
+@subsection @code{:config} is evaluated after loading package
+
+@findex :config
+The @code{:config} section is evaluated after the package has been
+loaded.  If the package is loaded immediately, this happens
+immediately after that, but if loading is done lazily (@pxref{Loading
+Packages}), this is deferred until after the package has been loaded.
+
+In general, you should keep @code{:init} forms as simple and quick as
+possible, and put as much as you can get away with into the
+@code{:config} section.  That way, deferred loading can help your
+Emacs start as quickly as possible.
+
+@node Best practices
+@subheading When to use @code{:preface}, @code{:config} and @code{:init}?
+@cindex tips for using @code{:preface}, @code{:config}, @code{:init}
+
+Where possible, it is better to avoid @code{:preface}, @code{:config}
+and @code{:init}.  Instead, prefer autoloading keywords such as
+@code{:bind} (@pxref{Key bindings}), @code{:hook} (@pxref{Hooks}), and
+@code{:mode} (@pxref{Modes and interpreters}), as they will take care
+of setting up autoloads for you without any need for boilerplate code.
+For example, consider the following declaration:
+
+@lisp
+@group
+(use-package foo
+  :init
+  (add-hook 'some-hook 'foo-mode))
+@end group
+@end lisp
+
+@noindent
+This has two problems.  First, it will unconditionally load the
+package @samp{foo} on startup, which will make things slower.  You can
+fix this by adding @w{@code{:defer t}}:
+
+@lisp
+@group
+(use-package foo
+  :defer t
+  :init
+  (add-hook 'some-hook 'foo-mode))
+@end group
+@end lisp
+
+@noindent
+This is better, as @samp{foo} is now only loaded when it is actually
+needed (that is, when the hook @samp{some-hook} is run).
+
+The second problem is that there is a lot of boilerplate that you have
+to write.  In this case, it might not be so bad, but avoiding that was
+what use-package was made to allow.  The better option in this case is
+therefore to use @code{:hook} (@pxref{Hooks}), which also implies
+@w{@code{:defer t}}.  The above is thereby reduced down to:
+
+@lisp
+@group
+(use-package foo
+  :hook some-hook)
+@end group
+@end lisp
+
+Now use-package will set up autoloading for you, and your Emacs
+startup time will not suffer one bit.
+
+@node Key bindings
+@section Key bindings
+
+@cindex binding keys for package commands
+@cindex key bindings for package commands
+One common thing to do when loading a package is to bind keys to
+commands within that module.  Without use-package, this would be done
+using a combination of @code{keymap-local-set},
+@code{keymap-global-set} and various autoloads.  With use-package, you
+can simplify this using the @code{:bind} keyword, as described in this
+section.
+
+@menu
+* Global keybindings::          Bindings you can use anywhere.
+* Binding in keymaps::          Bindings for particular modes.
+* Binding to a keymap::         Binding a key to a keymap.
+* Binding to repeat-maps::      Binding repeating keys.
+* Displaying keybindings::      Displaying personal key bindings.
+@end menu
+
+@node Global keybindings
+@subsection Global keybindings
+@cindex global keybindings
+
+@findex :bind
+To bind keys globally, the @code{:bind} keyword takes as its argument
+either a single cons or a list of conses.  Each cons has the form
+@w{@code{(@var{key} . @var{command})}}, where @var{key} is a string
+indicating the key to bind, and @var{command} is the name of a command
+(a symbol).  The syntax for the keys is similar to the syntax used by
+the @code{kbd} function (see @ref{Init Rebinding,,, emacs, GNU Emacs
+Manual}, for more information).
+
+@subheading Using @code{:bind} with a single cons
+
+Here is an example of using a single cons:
+
+@lisp
+@group
+(use-package ace-jump-mode
+  :bind ("C-." . ace-jump-mode))
+@end group
+@end lisp
+
+@noindent
+This does two things: first, it creates an autoload for the
+@code{ace-jump-mode} command and defers loading of the
+@code{ace-jump-mode} package until you actually use it.  Second, it
+binds the key @code{C-.} to that command globally.
+
+@subheading Using @code{:bind} with a list of conses
+
+Here is an example of using @code{:bind} with a list of conses:
+
+@lisp
+@group
+(use-package hi-lock
+  :bind (("M-o l" . highlight-lines-matching-regexp)
+         ("M-o r" . highlight-regexp)
+         ("M-o w" . highlight-phrase)))
+@end group
+@end lisp
+
+@noindent
+This binds the three key sequences to the corresponding commands.
+
+@subheading Using special keys
+@cindex binding function keys with @code{:bind}
+@cindex @code{:bind}, and function keys
+
+@c FIXME: TAB vs [tab] -- is letter-case important?  In general, these
+@c are two different keys: one is an ASCII character, the other a
+@c function key on GUI frames.
+Inside key strings, special keys like @kbd{TAB} or @kbd{F1}--@kbd{F12}
+have to be written inside angle brackets, e.g., @code{"C-<up>"}.
+@c FIXME: ``Some combinations''? which ones?
+Standalone special keys (and some combinations) can be written in
+square brackets, e.g.@ @code{[tab]} instead of @code{"<tab>"}.
+
+Examples:
+
+@lisp
+@group
+(use-package helm
+  :bind (("M-x" . helm-M-x)
+         ("M-<f5>" . helm-find-files)
+         ([f10] . helm-buffers-list)
+         ([S-f10] . helm-recentf)))
+@end group
+@end lisp
+
+@subheading Remapping commands
+@cindex remapping commands with @code{:bind}
+@cindex @code{:bind}, and remapping of commands
+
+Remapping of commands with @code{:bind} and @code{bind-key} works as
+expected, because when the binding is a vector, it is passed straight
+to @code{define-key}.  @xref{Remapping Commands,,, elisp, GNU Emacs
+Lisp Reference Manual}), for more information about command remapping.
+For example, the following declaration will rebind
+@code{fill-paragraph} (bound to @kbd{M-q} by default) to
+@code{unfill-toggle}:
+
+@lisp
+@group
+(use-package unfill
+  :bind ([remap fill-paragraph] . unfill-toggle))
+@end group
+@end lisp
+
+@c FIXME: Should the below be an Appendix?
+@subheading What @code{:bind} does behind the scenes
+@cindex @code{:bind}, internals
+
+To understand what @code{:bind} does behind the scenes, it might be
+useful to consider an example:
+
+@lisp
+@group
+(use-package ace-jump-mode
+  :bind ("C-." . ace-jump-mode))
+@end group
+@end lisp
+
+@noindent
+This could be expressed in a much more verbose way with the
+@code{:commands} and @code{:init} keywords:
+
+@lisp
+@group
+(use-package ace-jump-mode
+  :commands ace-jump-mode
+  :init
+  (bind-key "C-." 'ace-jump-mode))
+@end group
+@end lisp
+
+@noindent
+Without using even the @code{:commands} keyword, we could also write
+the above like so:
+
+@lisp
+@group
+(use-package ace-jump-mode
+  :defer t
+  :init
+  (autoload 'ace-jump-mode "ace-jump-mode" nil t)
+  (bind-key "C-." 'ace-jump-mode))
+@end group
+@end lisp
+
+Although these three forms are all equivalent, the first form is
+usually the best, as it will save some typing.
+
+@node Binding in keymaps
+@subsection Key bindings in local keymaps
+@cindex local keybindings
+
+@findex :map@r{, inside} :bind
+Slightly different from binding a key to a keymap, is binding a key
+@emph{within} a local keymap that only exists after the package is
+loaded.  @code{use-package} supports this with a @code{:map} modifier,
+taking the local keymap to bind to:
+
+@lisp
+@group
+(use-package helm
+  :bind (:map helm-command-map
+         ("C-c h" . helm-execute-persistent-action)))
+@end group
+@end lisp
+
+@noindent
+The effect of this is to wait until @code{helm} has loaded, and then
+to bind the key sequence @kbd{C-c h} to
+@code{helm-execute-persistent-action} within Helm's local keymap,
+@code{helm-command-map}.
+
+Multiple uses of @code{:map} may be specified.  Any binding occurring
+before the first use of @code{:map} are applied to the global keymap:
+
+@lisp
+@group
+(use-package term
+  :bind (("C-c t" . term)
+         :map term-mode-map
+         ("M-p" . term-send-up)
+         ("M-n" . term-send-down)
+         :map term-raw-map
+         ("M-o" . other-window)
+         ("M-p" . term-send-up)
+         ("M-n" . term-send-down)))
+@end group
+@end lisp
+
+@node Binding to a keymap
+@subsection Binding to keymaps
+@cindex binding keys to keymaps
+
+@findex :bind-keymap
+Normally @code{:bind} expects that commands are functions that will be
+autoloaded from the given package.  However, this does not work if one of
+those commands is actually a keymap, since keymaps are not functions,
+and cannot be autoloaded using the built-in @code{autoload} function.
+
+To handle this case, @code{use-package} offers a special, limited
+variant of @code{:bind} called @code{:bind-keymap}.  The only difference
+is that the ``commands'' bound to by @code{:bind-keymap} must be keymaps
+defined in the package, rather than interactive functions.  This is handled
+behind the scenes by generating custom code that loads the package
+containing the keymap, and then re-executes your keypress after the
+first load, to reinterpret that keypress as a prefix key.
+
+For example:
+
+@lisp
+@group
+(use-package foo
+  :bind-keymap ("C-c p" . foo-command-map))
+@end group
+@end lisp
+
+@node Binding to repeat-maps
+@subsection Binding to repeat-maps
+@cindex keybinding for @code{repeat-mode} keymaps
+
+@findex :repeat-map@r{, inside} :bind
+@cindex @code{repeat-mode} and use-package, using
+A special case of binding within a local keymap is when that keymap is
+used by @code{repeat-mode} (@pxref{Repeating,,, emacs, GNU Emacs
+Manual}).  These keymaps are usually defined specifically for
+this.  Using the @code{:repeat-map} keyword, and passing it a name for
+the map it defines, will bind all the following keys inside that map, and
+(by default) set the @code{repeat-map} property of each bound command
+to that map.
+
+The following example creates a keymap called
+@code{git-gutter+-repeat-map}, makes four bindings in it, then sets
+the @code{repeat-map} property of each bound command
+(@code{git-gutter+-next-hunk}, @code{git-gutter+-previous-hunk},
+@code{git-gutter+-stage-hunks}, and @code{git-gutter+-revert-hunk}) to
+that keymap.
+
+@lisp
+@group
+(use-package git-gutter+
+  :bind
+  (:repeat-map git-gutter+-repeat-map
+   ("n" . git-gutter+-next-hunk)
+   ("p" . git-gutter+-previous-hunk)
+   ("s" . git-gutter+-stage-hunks)
+   ("r" . git-gutter+-revert-hunk)))
+@end group
+@end lisp
+
+@findex :exit@r{, inside} :repeat-map@r{ and} :bind
+@cindex binding commands used at end of repeat series
+Specifying @code{:exit} inside the scope of @code{:repeat-map} will
+prevent the @code{repeat-map} property from being set, so that the command
+can be used from within the repeat map, but after using it the repeat
+map will no longer be available.  This is useful for commands often used
+at the end of a series of repeated commands.  Example:
+
+@lisp
+@group
+(use-package git-gutter+
+  :bind
+  (:repeat-map my/git-gutter+-repeat-map
+   ("n" . git-gutter+-next-hunk)
+   ("p" . git-gutter+-previous-hunk)
+   ("s" . git-gutter+-stage-hunks)
+   ("r" . git-gutter+-revert-hunk)
+   :exit
+   ("c" . magit-commit-create)
+   ("C" . magit-commit)
+   ("b" . magit-blame)))
+@end group
+@end lisp
+
+@findex :continue@r{, inside} :repeat-map@r{ and} :bind
+Specifying @code{:continue} @emph{forces} setting the
+@code{repeat-map} property (just like @emph{not} specifying
+@code{:exit}), so the above snippet is equivalent to:
+
+@lisp
+@group
+(use-package git-gutter+
+  :bind
+  (:repeat-map my/git-gutter+-repeat-map
+   :exit
+   ("c" . magit-commit-create)
+   ("C" . magit-commit)
+   ("b" . magit-blame)
+   :continue
+   ("n" . git-gutter+-next-hunk)
+   ("p" . git-gutter+-previous-hunk)
+   ("s" . git-gutter+-stage-hunks)
+   ("r" . git-gutter+-revert-hunk)))
+@end group
+@end lisp
+
+@node Displaying keybindings
+@subsection Displaying personal keybindings
+@cindex display your keybindings
+
+@findex describe-personal-keybindings
+The @code{:bind} keyword uses the @code{bind-keys} macro from the
+@samp{bind-key.el} library to set up keybindings.  It keeps track of
+all keybindings you make, so that you can display them separately from
+the default keybindings.
+
+Use @w{@kbd{M-x describe-personal-keybindings}} to see all
+keybindings you've set using either the @code{:bind} keyword or the
+@code{bind-keys} macro.
+
+@node Hooks
+@section Hooks
+
+@cindex hooks
+@findex :hook
+The @code{:hook} keyword allows adding functions to hooks.  It takes
+@c FIXME: The actual forms accepted by :hook are different, see below!
+one argument of the form @var{hooks}, specifying one or more functions
+to add to one or more hooks.  For the purposes of @code{:hook}, the
+name of hook variables should always exclude the @samp{-hook} suffix.
+It is appended automatically for you, to save some typing.
+
+For example, consider the following @code{use-package} declaration
+that sets up autoloads for @code{company-mode} from the @samp{company}
+package, and adds @samp{company-mode} to @code{prog-mode-hook}:
+
+@lisp
+@group
+(use-package company
+  :commands company-mode
+  :init
+  (add-hook 'prog-mode-hook #'company-mode))
+@end group
+@end lisp
+
+Using @code{:hook}, this can be simplified to:
+
+@lisp
+@group
+(use-package company
+  :hook (prog-mode . company-mode))
+@end group
+@end lisp
+
+Here, @code{:hook} will automatically set up autoloads for the
+@code{company-mode} command, so there is no need to use
+@code{:commands}.
+
+The @code{:hook} keyword will also assume that the name of the
+function you want to add is the same as the package name with
+@samp{-mode} appended to it.  Taking this into account, you can
+simplify the above to the equivalent:
+
+@lisp
+@group
+(use-package company
+  :hook prog-mode)
+@end group
+@end lisp
+
+@cindex multiple hooks
+You can also provide a list of hooks.  When multiple hooks should be
+applied, the following examples are all equivalent:
+
+@lisp
+@group
+(use-package company
+  :hook (prog-mode text-mode))
+@end group
+
+@group
+(use-package company
+  :hook ((prog-mode text-mode) . company-mode))
+@end group
+
+@group
+(use-package company
+  :hook ((prog-mode . company-mode)
+         (text-mode . company-mode)))
+@end group
+
+@group
+(use-package company
+  :commands company-mode
+  :init
+  (add-hook 'prog-mode-hook #'company-mode)
+  (add-hook 'text-mode-hook #'company-mode))
+@end group
+@end lisp
+
+One common mistake when using @code{:hook} is to forget to omit the
+@samp{-hook} suffix, which, as already explained, is appended
+automatically.  Therefore, the following will not work, as it attempts
+to add a function to non-existent @code{prog-mode-hook-hook}:
+
+@lisp
+@group
+;; DOES NOT WORK
+(use-package ace-jump-mode
+  :hook (prog-mode-hook . ace-jump-mode))
+@end group
+@end lisp
+
+@vindex use-package-hook-name-suffix
+If you do not like this behavior, you can customize the user option
+@code{use-package-hook-name-suffix} to @code{nil}.  The value of this
+variable is @samp{"-hook"} by default.
+
+The use of @code{:hook}, as with @code{:bind}, @code{:mode},
+@code{:interpreter}, etc., causes the functions being hooked to
+implicitly be read as @code{:commands}.  This means that they will
+establish interactive @code{autoload} definitions for that module, if
+not already defined as functions), and so @code{:defer t} is also
+implied by @code{:hook}.
+
+@node Modes and interpreters
+@section Modes and interpreters
+@cindex @code{auto-mode-alist} customization
+@cindex @code{interpreter-mode-alist} customization
+@cindex setting up major modes
+
+@findex :mode
+@findex :interpreter
+Similar to @code{:bind}, you can use @code{:mode} and
+@code{:interpreter} to establish a deferred binding within the
+@code{auto-mode-alist} and @code{interpreter-mode-alist} variables
+(@pxref{Auto Major Mode,,, elisp, GNU Emacs Lisp Reference Manual}).
+The specifier to either keyword can be a cons cell, a list of cons
+cells, or a string or regexp.
+
+The following example reproduces the default @code{ruby-mode}
+configuration, exactly as it is in Emacs out-of-the-box.  That mode is
+enabled automatically when a file whose name matches the regexp
+@code{"\\.rb\\'"} (a file with the @file{.rb} extension), or when the
+first line of the file (known as the ``shebang'') matches the string
+@code{"ruby"}:
+
+@lisp
+@group
+(use-package ruby-mode
+  :mode "\\.rb\\'"
+  :interpreter "ruby")
+@end group
+@end lisp
+
+The default @code{python-mode} configuration can be reproduced using
+the declaration below.  Note that the package that should be loaded
+differs from the mode name in this case, so we must use a cons:
+
+@lisp
+@group
+;; The package is "python" but the mode is "python-mode":
+(use-package python
+  :mode ("\\.py\\'" . python-mode)
+  :interpreter ("python" . python-mode))
+@end group
+@end lisp
+
+Both the @code{:mode} and @code{:interpreter} keywords also accept a
+list of regexps:
+
+@lisp
+@group
+(use-package foo
+  ;; Equivalent to "\\(ba[rz]\\)\\'":
+  :mode ("\\.bar\\'" "\\.baz\\'")
+  ;; Equivalent to "\\(foo[ab]\\)":
+  :interpreter ("fooa" "foob"))
+@end group
+@end lisp
+
+@node Magic handlers
+@section Magic handlers
+@cindex @code{magic-mode-alist} customization
+
+@findex :magic
+@findex :magic-fallback
+Similar to @code{:mode} and @code{:interpreter}, you can also use
+@code{:magic} and @code{:magic-fallback} to cause certain function to
+be run if the beginning of a file matches a given regular expression,
+as if these regular expressions were added to @code{magic-mode-alist}
+and @code{magic-fallback-mode-alist} (@pxref{Auto Major Mode,,, elisp,
+GNU Emacs Lisp Reference Manual}).  The difference between
+@code{:magic} and @code{:magic-fallback}, is that the latter has a
+lower priority than @code{:mode}.
+
+Here is an example:
+
+@lisp
+@group
+(use-package pdf-tools
+  :magic ("%PDF" . pdf-view-mode)
+  :config
+  (pdf-tools-install :no-query))
+@end group
+@end lisp
+
+This registers an autoloaded command for @code{pdf-view-mode}, defers
+loading of @code{pdf-tools}, and runs @code{pdf-view-mode} if the
+beginning of a buffer matches the string @code{"%PDF"}.
+
+@node User options
+@section User options
+@cindex customization of variables
+@cindex variable customizations
+@cindex user options, setting
+
+@findex :custom
+In Emacs, you normally set customizable variables (user options) using
+the @code{M-x customize} interface (@pxref{Easy Customization,,,
+emacs, GNU Emacs Manual}).  We recommend this method for most users.
+However, it is also possible to set them in your @code{use-package}
+declarations by using the @code{:custom} keyword.
+
+@lisp
+@group
+(use-package comint
+  :defer t
+  :custom
+  (comint-buffer-maximum-size 20000 "Increase comint buffer size.")
+  (comint-prompt-read-only t "Make the prompt read only."))
+@end group
+@end lisp
+
+This is better than using @code{setq} in a @code{:config} block, as
+customizable variables might have some code associated with it that
+Emacs will execute when you assign values to them.  (In Emacs 29 and
+later, there is also the new @code{setopt} macro that does this for
+you.)
+
+Note that the values customized using @code{:custom} are @emph{not}
+saved in the standard Emacs @code{custom-file} (@pxref{Saving
+Customizations,,, emacs, GNU Emacs Manual}).  You should therefore set
+each user option using either the @code{:custom} keyword @emph{or}
+@w{@kbd{M-x customize-option}} command; the latter will save
+customized values in the Emacs @code{custom-file}.  Do not use both
+for the same variable, as this risks having conflicting values in your
+use-package declaration and your @code{custom-file}, which can lead to
+problems that are both tricky and tedious to debug.
+
+@node Faces
+@section Faces
+@cindex faces, setting
+@cindex customization of faces
+
+@findex :custom-face
+The @code{:custom-face} keyword allows customization of package's
+faces.  Example:
+
+@lisp
+@group
+(use-package eruby-mode
+  :custom-face
+  (eruby-standard-face ((t (:slant italic)))))
+@end group
+
+@group
+(use-package example
+  :custom-face
+  (example-1-face ((t (:foreground "LightPink"))))
+  (example-2-face ((t (:foreground "LightGreen"))) face-defspec-spec))
+@end group
+
+@group
+(use-package zenburn-theme
+  :preface
+  (setq my/zenburn-colors-alist
+        '((fg . "#DCDCCC") (bg . "#1C1C1C") (cyan . "#93E0E3")))
+  :custom-face
+  (region ((t (:background ,(alist-get my/zenburn-colors-alist 'cyan)))))
+  :config
+  (load-theme 'zenburn t))
+@end group
+@end lisp
+
+@node Hiding minor modes
+@section Hiding minor modes with diminish and delight
+@cindex hiding minor modes
+
+@code{use-package} supports the @file{diminish} and @file{delight}
+packages, both of which make it possible to remove or change minor mode
+strings in your mode-line.  Which one to use is up to you, but you
+should normally only use one or the other -- never both.@footnote{When
+in doubt, you might as well use @file{diminish}.}  To use either of them, you
+must first install the corresponding package from @acronym{GNU} @acronym{ELPA}.
+
+@menu
+* Diminish::                    Hiding minor modes with Diminish.
+* Delight::                     Hiding minor modes with Delight.
+@end menu
+
+@node Diminish
+@subsection Diminish
+
+@findex :diminish
+When diminish@footnote{The @file{diminish} package is installable from
+@acronym{GNU} @acronym{ELPA}.} is installed, you can use the @code{:diminish}
+keyword.  If @file{diminish} is not installed, the @code{:diminish} keyword
+does nothing.
+
+First, add the following declaration to the beginning of your init
+file.
+
+@lisp
+(use-package diminish :ensure t)
+@end lisp
+
+@noindent
+The optional @w{@code{:ensure t}} makes sure the package is installed
+if it isn't already (@pxref{Installing packages}).
+
+The @code{:diminish} keyword takes as its argument either a minor mode
+symbol, a cons of the symbol and its replacement string, or just a
+replacement string, in which case the minor mode symbol is guessed to
+be the package name with @samp{-mode} appended at the end:
+
+@lisp
+@group
+(use-package abbrev
+  :diminish abbrev-mode
+  :config
+  (if (file-exists-p abbrev-file-name)
+      (quietly-read-abbrev-file)))
+@end group
+@end lisp
+
+@node Delight
+@subsection Delight
+
+@findex :delight
+When @file{delight}@footnote{The @file{delight} package is installable from
+@acronym{GNU} @acronym{ELPA}.} is installed, you can use the
+@code{:delight} keyword.  If @file{delight} is not installed, the
+@code{:delight} keyword does nothing.
+
+First, add the following declaration to the beginning of your init
+file.
+
+@lisp
+(use-package delight :ensure t)
+@end lisp
+
+@noindent
+The optional @w{@code{:ensure t}} makes sure the package is installed
+if it isn't already (@pxref{Installing packages}).
+
+The @code{:delight} keyword takes as its argument a minor mode symbol,
+a replacement string, or quoted mode line data (in which case the
+minor mode symbol is assumed to be the package name with @samp{-mode}
+appended at the end), both of these, or several lists of both.
+@xref{Mode Line Data,,, elisp, GNU Emacs Lisp Reference Manual}.  If
+no arguments are provided, the default mode name is hidden completely.
+
+For example, the following hides everything for the @samp{foo-mode}
+minor mode in the @samp{foo} package:
+
+@lisp
+@group
+(use-package foo
+  :delight)
+@end group
+@end lisp
+
+If the mode name doesn't match the package name with @samp{-mode}
+appended, provide a symbol instead.  For example, the following hides
+@code{auto-revert-mode} from the mode line:
+
+@lisp
+@group
+;; Don't show anything for auto-revert-mode, which doesn't match
+;; its package name.
+(use-package autorevert
+  :delight auto-revert-mode)
+@end group
+@end lisp
+
+You can also use arbitrary Lisp code as argument of @code{:delight}.
+For example, to replace @samp{foo-mode} with the value of the current
+buffer:
+
+@lisp
+@group
+(use-package foo
+  :delight '(:eval buffer-file-name))
+@end group
+@end lisp
+
+Here is an example of hiding several built-in minor modes:
+
+@lisp
+@group
+;; Completely hide visual-line-mode and change auto-fill-mode to " AF".
+(use-package emacs
+  :delight
+  (auto-fill-function " AF")
+  (visual-line-mode))
+@end group
+@end lisp
+
+@c ----------------------------------------------------------------------------
+@node Installing packages
+@chapter Installing packages automatically
+
+The standard Emacs package manager is documented in the Emacs manual
+(@pxref{Package Installation,,, emacs, GNU Emacs Manual}).  The
+@code{use-package} macro provides the @code{:ensure} and @code{:pin}
+keywords that interface with that package manager to automatically
+install packages.  This is particularly useful if you use your init
+file on more than one system.
+
+@menu
+* Install package::
+* Pinning packages::
+* Other package managers::
+@end menu
+
+@node Install package
+@section Installing package
+@cindex installing packages from archives
+
+@findex :ensure
+The @code{:ensure} keyword makes use-package ask the Emacs package
+manager to install a package if it is not already present on your
+system.
+
+For example:
+
+@lisp
+@group
+(use-package magit
+  :ensure t)
+@end group
+@end lisp
+
+If you need to install a different package from the one named by
+@code{use-package}, you can use a symbol:
+
+@lisp
+@group
+(use-package tex
+  :ensure auctex)
+@end group
+@end lisp
+
+@vindex use-package-always-ensure
+You can customize the user option @code{use-package-always-ensure} to
+a non-@code{nil} value if you want this behavior to be global for all
+packages:
+
+@lisp
+@group
+(require 'use-package-ensure)
+(setq use-package-always-ensure t)
+@end group
+@end lisp
+
+@noindent
+You can override the above setting for a single package by adding
+@w{@code{:ensure nil}} to its declaration.
+
+@node Pinning packages
+@section Pinning packages using @code{:pin}
+@cindex installing package from specific archive
+@cindex pinning a package to archive
+
+@findex :pin
+use-package can @dfn{pin} a package to a specific archive using the
+@code{:pin} keyword.@footnote{The @code{:pin} keyword has no effect on
+Emacs versions older than 24.4.}  This allows you to mix and match
+packages from different archives.  The primary use-case for this is
+preferring to install packages from @acronym{GNU} @acronym{ELPA} or
+@acronym{NonGNU} @acronym{ELPA} (indicated by @code{gnu} and @code{nongnu},
+respectively), while installing specific packages from third-party
+archives.
+
+For example:
+
+@lisp
+@group
+(use-package company
+  :ensure t
+  :pin gnu)   ; GNU ELPA
+@end group
+@end lisp
+
+@vindex use-package-always-pin
+Unfortunately, the third-party archive @acronym{MELPA} uses a
+versioning scheme based on dates, which means that packages from that
+archive are always preferred.  If you are using that archive, we
+strongly encourage you to customize @code{use-package-always-pin} to
+@code{nongnu}.  This guarantees that you are using a version of that
+package that has been specifically marked for release by its
+developer, and not a development snapshot.
+
+@cindex manual update of packages
+@c FIXME: This needs clarifying.  AFAIK, :ensure does not update packages.
+If you want to manually keep a package updated and ignore upstream
+updates, you can pin it to @samp{manual}.  This will work as long as
+you have not customized a repository to use that name in the
+@code{package-archives} variable.
+
+Example:
+
+@lisp
+@group
+(use-package org
+  :ensure t
+  ;; ignore org-mode from upstream and use a manually installed version
+  :pin manual)
+@end group
+@end lisp
+
+@code{use-package} signals an error if you try to pin a package to an
+archive that is not configured using @code{package-archives} (except
+from the special @samp{manual} archive).
+
+@node Other package managers
+@section Non-standard package managers
+@cindex non-standard package managers
+@cindex package managers, other than @file{package.el}
+@cindex installing using non-standard package managers
+
+By default, use-package assumes that you are using the Emacs built-in
+@file{package.el} package manager.  We expect that most users will
+find that it is capable enough, even for advanced use cases.
+
+@vindex use-package-ensure-function
+However, some users might prefer to use a third-party package manager
+for a specific circumstance or use case.  By setting the user option
+@code{use-package-ensure-function} to the name of a function, you can
+direct @code{:ensure} to use a different package manager for
+installing packages.
+
+For more details, please see the documentation of the package manager
+you are using.  If you run into any bugs, it is often best to report
+them directly to the developers of that package manager.
+
+@c ----------------------------------------------------------------------------
+@node Byte-compiling
+@chapter Byte-compiling your init file
+@cindex byte-compiling your init file
+
+Some users might want to byte-compile their init file to make Emacs
+startup faster.  This is not recommended in most cases, as the
+speed-up is usually too small to be worth it, and it can lead to
+confusion if the byte-compiled files are out-of-date.  If you still
+want to do it, this chapter explains how to do that.
+
+@code{use-package} always loads every library that it can while a file
+is being byte-compiled.  This helps silence spurious warnings about
+unknown variables and functions.
+
+@findex :defines
+@findex :functions
+@cindex silence byte-compilation warnings
+However, there are times when this is just not enough.  For those
+times, use the @code{:defines} and @code{:functions} keywords to
+introduce dummy variable and function declarations solely for the sake
+of silencing byte-compiler warnings.  For example:
+
+@lisp
+@group
+(use-package texinfo
+  :defines texinfo-section-list
+  :commands texinfo-mode
+  :init
+  (add-to-list 'auto-mode-alist '("\\.texi$" . texinfo-mode)))
+@end group
+@end lisp
+
+If you need to silence a missing function warning, you can use
+@code{:functions}:
+
+@lisp
+@group
+(use-package ruby-mode
+  :mode "\\.rb\\'"
+  :interpreter "ruby"
+  :functions inf-ruby-keys
+  :config
+  (defun my-ruby-mode-hook ()
+    (require 'inf-ruby)
+    (inf-ruby-keys))
+  (add-hook 'ruby-mode-hook 'my-ruby-mode-hook))
+@end group
+@end lisp
+
+@findex :no-require
+@cindex prevent a package from loading at compile-time
+@cindex package loading at byte-compilation time, prevent
+Normally, @code{use-package} will load each package at compile time
+before compiling the configuration, to ensure that any necessary
+symbols are in scope to satisfy the byte-compiler.  At times this can
+cause problems, since a package may have special loading requirements,
+and all that you want to use @code{use-package} for is to add a
+configuration to the @code{eval-after-load} hook.  In such cases, use
+the @code{:no-require} keyword:
+
+@lisp
+@group
+(use-package foo
+  :no-require t
+  :config
+  (message "Evaluate this immediately after loading `foo'"))
+@end group
+@end lisp
+
+@c ----------------------------------------------------------------------------
+@node Troubleshooting
+@chapter Troubleshooting
+
+@cindex troubleshooting use-package
+@cindex debugging use-package
+If an error occurs while initializing or configuring a package, this
+will not stop your Emacs from loading.  Instead, @code{use-package}
+captures the error and reports it in a special @file{*Warnings*} popup
+buffer, so that you can debug the situation in an otherwise functional
+Emacs.
+
+If you are having trouble when starting Emacs, you can pass Emacs the
+@samp{--debug-init} command line flag.  @xref{Initial Options,,,
+emacs, GNU Emacs Manual}.  To get even more information when using
+that flag, add the following to your init file (these options are
+documented below):
+
+@lisp
+@group
+(when init-file-debug
+  (setq use-package-verbose t
+        use-package-expand-minimally nil
+        use-package-compute-statistics t
+        debug-on-error t))
+@end group
+@end lisp
+
+@cindex reporting bugs
+@cindex expanding macro, for troubleshooting
+Since @code{use-package} is a macro, the first step when you need to
+dig deeper is usually to see what Emacs Lisp code your declaration
+expands to.  You can either use the command @w{@kbd{M-x
+pp-macroexpand-last-sexp}}, or wrap the use-package declaration in
+@code{macroexpand} and evaluate it.  It is a good idea to include
+their output in any bugs you file for use-package.
+
+@menu
+* Troubleshooting Options::
+* Gathering Statistics::
+* Disabling a package::
+@end menu
+
+@node Troubleshooting Options
+@section Options that help when troubleshooting
+@cindex options for troubleshooting
+@cindex troubleshooting, options that help
+
+@vindex use-package-expand-minimally
+By default, use-package will attempts to catch and report errors that
+occur during expansion of use-package declarations in your init file.
+Customize the user option @code{use-package-expand-minimally} to a
+non-@code{nil} value to disable this checking.
+
+@findex :catch
+This behavior may be overridden locally using the @code{:catch}
+keyword.  If @code{t} or @code{nil}, it enables or disables catching
+errors at load time.  It can also be a function taking two arguments:
+the keyword being processed at the time the error was encountered, and
+the error object (as generated by @code{condition-case}).  For
+example:
+
+@lisp
+@group
+(use-package example
+  ;; Note that errors are never trapped in the preface, since
+  ;; doing so would hide definitions from the byte-compiler.
+  :preface (message "I'm here at byte-compile and load time")
+  :init (message "I'm always here at startup")
+  :config
+  (message "I'm always here after the package is loaded")
+  (error "oops")
+  ;; Don't try to (require 'example), this is just an example!
+  :no-require t
+  :catch (lambda (keyword err)
+           (message (error-message-string err))))
+@end group
+@end lisp
+
+Evaluating the above form will print these messages:
+
+@verbatim
+I'm here at byte-compile and load time
+I'm always here at startup
+Configuring package example...
+I'm always here after the package is loaded
+oops
+@end verbatim
+
+@node Gathering Statistics
+@section Gathering Statistics
+@cindex gathering use-package statistics
+@cindex usage statistics for use-package
+
+@vindex use-package-verbose
+When a package is loaded, and if you have @code{use-package-verbose}
+set to @code{t}, or if the package takes longer than 0.1 seconds to
+load, you will see a message to indicate this loading activity in the
+@code{*Messages*} buffer.  The same will happen for configuration, or
+@code{:config} blocks, that take longer than 0.1 seconds to execute.
+
+@vindex use-package-compute-statistics
+If you'd like to see a summary how many packages you've loaded, what
+stage of initialization they've reached, and how much aggregate time
+they've spent (roughly), you can customize the user option
+@code{use-package-compute-statistics} to a non-@code{nil} value.  Then
+reload your packages, normally by restarting Emacs, to make sure that
+use-package can gather statistics for all your packages.
+
+@cindex use-package-report
+Run the command @kbd{M-x use-package-report} to see the results.  The
+buffer displayed is a tabulated list.  To sort rows based on a
+particular column, move point to it and type @kbd{S}, or click the
+column name at the top of the buffer on graphical displays.
+
+@findex use-package-reset-statistics
+To reset all statistics that use-package has gathered for the current
+Emacs invocation, run the command @kbd{M-x use-package-reset-statistics}.
+
+Note that if you are setting @code{use-package-compute-statistics}
+directly in your init file, and not with @code{customize}, you must do
+this after loading @code{use-package}, but before any
+@code{use-package} forms.
+
+@node Disabling a package
+@section Disabling a package
+@cindex disable package
+
+@findex :disabled
+The @code{:disabled} keyword inhibits loading a package, and all its
+customizations.  It is equivalent to commenting out or deleting the
+definition.
+
+You could use this, for example, to temporarily disable a package that
+you're having difficulties with, or to avoid loading a package that
+you're not currently using.
+
+This example disables the @samp{foo} package:
+
+@lisp
+@group
+(use-package foo
+  :disabled)
+@end group
+@end lisp
+
+When byte-compiling your init file, use-package omits disabled
+declarations from the output entirely, in order to make Emacs startup
+faster.
+
+@c ----------------------------------------------------------------------------
+@node Keyword extensions
+@appendix Keyword extensions
+@cindex keyword extension
+@cindex extending use-package keywords
+
+use-package is based on an extensible framework that makes it easy for
+package authors to add new keywords, or modify the behavior of
+existing keywords.
+
+Some keyword extensions are included with @code{use-package}, and can
+be optionally enabled.
+
+@menu
+* use-package-ensure-system-package::
+* Creating an extension::
+@end menu
+
+@node use-package-ensure-system-package
+@appendixsec :use-package-ensure-system-package
+
+@findex :ensure-system-package
+The @code{:ensure-system-package} keyword allows you to ensure certain
+executables are available on your system alongside your package
+declarations.@footnote{On macOS, your @code{exec-path} might be
+different if you are starting Emacs as a GUI app instead of from a
+shell.  If you find that Emacs on macOS cannot find some executables
+that you know are already installed, you could try the
+@uref{https://github.com/purcell/exec-path-from-shell,@samp{exec-path-from-shell}}
+package.}
+
+To use this extension, add this immediately after loading
+@code{use-package}:
+
+@lisp
+(use-package use-package-ensure-system-package)
+@end lisp
+
+Now you can use the @code{:ensure-system-package} keyword.
+Here's an example usage:
+
+@lisp
+@group
+(use-package foo
+  :ensure-system-package foo)
+@end group
+@end lisp
+
+This will expect a global binary package to exist called @code{foo}.
+If it does not, it will use your system package manager to attempt an
+install of a binary by the same name asynchronously.  This requires
+the @acronym{GNU} @acronym{ELPA} package
+@uref{https://gitlab.com/jabranham/system-packages,@samp{system-packages}},
+so for this to work you must install that first.
+
+One way of making sure it is installed is with @code{use-package}
+together with @code{:ensure}.
+
+@lisp
+@group
+(use-package system-packages
+  :ensure t)
+@end group
+@end lisp
+
+For example, on a Debian GNU/Linux system, this would call
+@samp{apt-get install foo}.
+
+If the package is named differently than the binary, you can use a
+cons in the form of @code{(binary . package-name)}.  For example:
+
+@lisp
+@group
+(use-package foo
+  :ensure-system-package
+  (foocmd . foo))
+@end group
+@end lisp
+
+On a Debian GNU/Linux system, this would call @code{apt install foo}
+if Emacs could not locate the executable @code{foocmd}.@footnote{For
+manual testing, you could use the @code{executable-find} function,
+which is what @samp{system-packages} uses internally.}
+
+@code{:ensure-system-package} can also take a cons where the
+@code{cdr} is a string that will get called by
+@code{(async-shell-command)} to install if it isn't found.  This does
+not depend on any external package.
+
+@lisp
+@group
+(use-package tern
+  :ensure-system-package (tern . "npm i -g tern"))
+@end group
+@end lisp
+
+To install several packages, you can pass in a list of conses:
+
+@lisp
+@group
+(use-package ruby-mode
+  :ensure-system-package
+  ((rubocop     . "gem install rubocop")
+   (ruby-lint   . "gem install ruby-lint")
+   (ripper-tags . "gem install ripper-tags")
+   (pry         . "gem install pry")))
+@end group
+@end lisp
+
+Finally, in case the package dependency does not provide a global
+executable, you can ensure that packages exist by checking the
+presence of a file by providing a string like so:
+
+@lisp
+@group
+(use-package dash-at-point
+  :if (eq system-type 'darwin)
+  :ensure-system-package
+  ("/Applications/Dash.app" . "brew cask install dash"))
+@end group
+@end lisp
+
+@code{:ensure-system-package} will use @code{system-packages-install}
+to install system packages, except where a custom command has been
+specified, in which case it will be executed verbatim by
+@code{async-shell-command}.
+
+The user options @code{system-packages-package-manager} and
+@code{system-packages-use-sudo} are honored, but not for custom
+commands.  Custom commands should include the call to sudo in the
+command if needed.
+
+@node Creating an extension
+@appendixsec How to create an extension keyword
+@cindex extension keywords
+
+This section describes how to create a new keyword.
+
+@enumerate
+@item
+Add the keyword.
+
+The first step is to add your keyword at the right place in
+@code{use-package-keywords}.  This list determines the order in which
+things will happen in the expanded code.  You should never change this
+order, but it gives you a framework within which to decide when your
+keyword should fire.
+
+@item
+Create a normalizer.
+
+The job of the normalizer is take a list of arguments (possibly
+@code{nil}), and turn it into the single argument (which could still
+be a list) that should appear in the final property list used by
+@code{use-package}.
+
+Define a normalizer for your keyword by defining a function named
+after the keyword, for example:
+
+@lisp
+@group
+(defun use-package-normalize/:pin (name-symbol keyword args)
+  (use-package-only-one (symbol-name keyword) args
+    (lambda (label arg)
+      (cond
+       ((stringp arg) arg)
+       ((symbolp arg) (symbol-name arg))
+       (t
+        (use-package-error
+         ":pin wants an archive name (a string)"))))))
+@end group
+@end lisp
+
+@item
+Create a handler.
+
+Once you have a normalizer, you must create a handler for the keyword.
+
+Handlers can affect the handling of keywords in two ways.  First, they
+can modify the @code{state} plist before recursively processing the
+remaining keywords, to influence keywords that pay attention to the
+state (one example is the state keyword @code{:deferred}, not to be
+confused with the @code{use-package} keyword @code{:defer}).  Then,
+once the remaining keywords have been handled and their resulting
+forms returned, the handlers may manipulate, extend, or just ignore
+those forms.
+
+The task of each handler is to return a @emph{list of forms}
+representing code to be inserted.  It does not need to be a
+@code{progn} list, as this is handled automatically in other places.
+Thus it is common to see the idiom of using @code{use-package-concat}
+to add new functionality before or after a code body, so that only the
+minimum code necessary is emitted as the result of a
+@code{use-package} expansion.
+
+This is an example handler:
+
+@lisp
+@group
+(defun use-package-handler/:pin (name-symbol keyword archive-name rest state)
+  (let ((body (use-package-process-keywords name-symbol rest state)))
+    ;; This happens at macro expansion time, not when the expanded code is
+    ;; compiled or evaluated.
+    (if (null archive-name)
+        body
+      (use-package-pin-package name-symbol archive-name)
+      (use-package-concat
+       body
+       `((push '(,name-symbol . ,archive-name)
+               package-pinned-packages))))))
+@end group
+@end lisp
+
+@item
+Test it.
+
+After the keyword has been inserted into @code{use-package-keywords},
+and a normalizer and a handler has been defined, you can now test the
+keyword by seeing how usages of the keyword will expand.  For this,
+use @w{@kbd{M-x pp-macroexpand-last-sexp}} with the cursor set
+immediately after the @code{(use-package @dots{})} expression.
+@end enumerate
+
+@c ----------------------------------------------------------------------------
+@node History
+@appendix History and acknowledgments
+
+use-package was written by John Wiegley.  Its development started in
+2012, and it got merged into Emacs in 2022, in preparation of the
+release of Emacs 29.1.
+
+Dozens of people have contributed to use-package over the years with
+bug reports, documentation and code.  They are too many to list here,
+but we thank them all for their contributions.
+
+This Texinfo manual was written by Stefan Kangas, as a significant
+rewrite of the old use-package manual and @file{README}.
+
+@node GNU Free Documentation License
+@appendix GNU Free Documentation License
+@include doclicense.texi
+
+@node Index
+@unnumbered Index
+@printindex cp
+
+@bye
diff --git a/etc/DEBUG b/etc/DEBUG
index ef9160a209..01c75f8da7 100644
--- a/etc/DEBUG
+++ b/etc/DEBUG
@@ -1002,6 +1002,28 @@ Address sanitization is incompatible with 
undefined-behavior
 sanitization, unfortunately.  Address sanitization is also
 incompatible with the --with-dumping=unexec option of 'configure'.
 
+*** Address poisoning/unpoisoning
+
+When compiled with address sanitization, Emacs will also try to mark
+dead/free lisp objects as poisoned, forbidding them from being
+accessed without being unpoisoned first.  This adds an extra layer
+of checking with objects in internal free lists, which may otherwise
+evade traditional use-after-free checks. To disable this, add
+'allow_user_poisoning=0' to ASAN_OPTIONS, or build Emacs with
+'-DGC_ASAN_POISON_OBJECTS=0' in CFLAGS.
+
+While using GDB, memory addresses can be inspected by using helper
+functions additionally provided by the ASan library:
+
+  (gdb) call __asan_describe_address(ptr)
+
+To check whether an address range is poisoned or not, use:
+
+  (gdb) call __asan_region_is_poisoned(ptr, 8)
+
+Additional functions can be found in the header
+'sanitizer/asan_interface.h' in your compiler's headers directory.
+
 ** Running Emacs under Valgrind
 
 Valgrind <https://valgrind.org/> is free software that can be useful
diff --git a/etc/ERC-NEWS b/etc/ERC-NEWS
index d0d84d0a98..76439f1d06 100644
--- a/etc/ERC-NEWS
+++ b/etc/ERC-NEWS
@@ -45,8 +45,8 @@ With the overhaul of the services module temporarily shelved 
and the
 transition to SASL-based authentication still underway, users may feel
 left in the lurch to endure yet another release cycle of backtick
 hell.  For some, auth-source may provide a workaround in the form of
-nonstandard server passwords.  See the "Connection" node in the manual
-under the subheading "Password".
+nonstandard server passwords.  See the section titled "auth-source" in
+the Integrations chapter of ERC's manual.
 
 ** Rudimentary SASL support has arrived.
 A new module, 'erc-sasl', now ships with ERC 5.5.  See the SASL
diff --git a/etc/HELLO b/etc/HELLO
index 7bc12063f8..fbe65a451e 100644
--- a/etc/HELLO
+++ b/etc/HELLO
@@ -114,7 +114,7 @@ Thai (ภาษาไทย)      สวัสดีครับ / สวัสดี
 Tibetan (བོད་སྐད་)     བཀྲ་ཤིས་བདེ་ལེགས༎
 Tigrigna (ትግርኛ)        ሰላማት
 Tirhuta (𑒞𑒱𑒩𑒯𑒳𑒞𑒰)      𑒣𑓂𑒩𑒢𑒰𑒧 / 𑒮𑒲𑒞𑒰𑒩𑒰𑒧
-Turkish (Türkçe)       Merhaba
+Turkish (Türkçe)       Esenlikler / Merhaba
 Ukrainian (українська) Вітаю / Добрий день! / Привіт
 Vietnamese (tiếng Việt)        Chào bạn
 Wancho (𞋒𞋀𞋉𞋃𞋕)         𞋂𞋈𞋛
diff --git a/etc/NEWS b/etc/NEWS
index 8f5b17fb4a..af7f1050b7 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -40,14 +40,59 @@ connection.
 
 
 * Changes in Specialized Modes and Packages in Emacs 30.1
+---
+** Variable order and truncation can now be configured in gdb-many-window mode.
+The new variable 'gdb-locals-table-row-config' allows users to
+configure the order and max length of various properties in the local
+variables buffer when using 'gdb-many-windows'.
+
+By default, this variable is set to write the properties in the order:
+name, type and value, where the name and type are truncated to 20
+characters, and the value is truncated according to the value of
+'gdb-locals-value-limit'.
+
+If you want to get back the old behavior, set
+'gdb-locals-table-row-config' to  the value
+
+  ((type . 0)(name . 0)(value . ,gdb-locals-value-limit)).
 
 ** VC
 
 ---
-*** New user option 'vc-git-shortlog-switches'
-String or list of strings giving Git log switches for shortlogs, such
-as 'C-x v L'.  'vc-git-log-switches' is no longer used for shortlogs.
+*** New user option 'vc-git-shortlog-switches'.
+This is a string or a list of strings that specifies the Git log
+switches for shortlogs, such as the one produced by 'C-x v L'.
+'vc-git-log-switches' is no longer used for shortlogs.
+
+** bs
 
+---
+*** New user option 'bs-default-action-list'.
+You can now configure how to display the "*buffer-selection*" buffer
+using this new option.  (Or set 'display-buffer-alist' directly.)
+
+** Eshell
+
++++
+*** New splice operator for Eshell dollar expansions.
+Dollar expansions in Eshell now let you splice the elements of the
+expansion in-place using '$@expr'.  This makes it easier to fill lists
+of arguments into a command, such as when defining aliases.  For more
+information, see the "(eshell) Dollars Expansion" node in the Eshell
+manual.
+
++++
+*** 'eshell-read-aliases-list' is now an interactive command.
+After manually editing 'eshell-aliases-file', you can use
+'M-x eshell-read-aliases-list' to load the edited aliases.
+
+** Prog Mode
++++
+*** New command 'prog-fill-reindent-defun'
+This command either fills a single paragraph in a defun, such as a
+doc-string, or a comment, or (re)indents the surrounding defun if
+point is not in a comment or a string.  It is by default bound to
+'M-q' in 'prog-mode' and all its descendants.
 
 * New Modes and Packages in Emacs 30.1
 
diff --git a/etc/NEWS.29 b/etc/NEWS.29
index d38ccadba6..017fd850b4 100644
--- a/etc/NEWS.29
+++ b/etc/NEWS.29
@@ -30,6 +30,44 @@ Use '--with-native-compilation=aot' to specify that all the 
Lisp files
 in the Emacs tree should be natively compiled ahead of time.  (This is
 slow on most machines.)
 
++++
+** Emacs can be built with the tree-sitter parsing library.
+This library, together with grammar libraries, provides incremental
+parsing capabilities for several popular programming languages and
+other formatted files.  Emacs built with this library offers major
+modes, described elsewhere in this file, that are based on the
+tree-sitter's parsers.  If you have the tree-sitter library
+installed, the configure script will automatically include it in the
+build; use '--without-tree-sitter' at configure time to disable that.
+
+Emacs modes based on the tree-sitter library require an additional
+grammar library for each mode.  These grammar libraries provide the
+tree-sitter library with language-specific lexical analysis and
+parsing capabilities, and are developed separately from the
+tree-sitter library itself.  If you don't have a grammar library
+required by some Emacs major mode, and your distro doesn't provide it
+as an installable package, you can compile and install such a library
+yourself.  Many libraries can be downloaded from the tree-sitter site:
+
+    https://github.com/tree-sitter
+
+To compile such a library, compile the files "scanner.c" and "parser.c"
+(sometimes named "scanner.cc" and "parser.cc") in the "src" subdirectory
+of the library's source tree using the C or C++ compiler, then link
+these two files into a shared library named "libtree-sitter-LANG.so",
+where LANG is the name of the language supported by the grammar as it
+is expected by the Emacs major mode (for example, "c" for 'c-ts-mode',
+"cpp" for 'c++-ts-mode', "python" for 'python-ts-mode', etc.).  Then place
+the shared library you've built in the same directory where you keep
+the other shared libraries used by Emacs, or in the "tree-sitter"
+subdirectory of your 'user-emacs-directory', or in a directory
+mentioned in the variable 'treesit-extra-load-path'.
+
+You only need to install language grammar libraries required by the
+Emacs modes you will use, as Emacs loads these libraries only when the
+corresponding mode is turned on in some buffer for the first time in
+an Emacs session.
+
 +++
 ** Emacs can be built with built-in support for accessing SQLite databases.
 This uses the popular sqlite3 library, and can be disabled by using
@@ -105,16 +143,6 @@ configuration on X is known to have problems, such as 
undesirable
 frame positioning and various issues with keyboard input of sequences
 such as 'C-;' and 'C-S-u'.
 
----
-** The implementation of overlays has changed.
-Emacs now uses an implementation of overlays that is much more
-efficient than the original one, and should speed up all the
-operations that involve overlays, especially when there are lots of
-them in a buffer.  However, no changes in behavior of overlays should
-be visible on the Lisp or user level, with the exception of better
-performance and the order of overlays returned by functions that don't
-promise any particular order.
-
 ---
 ** The docstrings of preloaded files are not in "etc/DOC" any more.
 Instead, they're fetched as needed from the corresponding ".elc" file,
@@ -1383,6 +1411,11 @@ language.
 This is a variant of the 'slovak' input method, which corresponds to
 the QWERTY Slovak keyboards.
 
+---
+*** New input method 'cyrillic-chuvash'.
+This input method is based on the russian-computer, and is intended
+for the Chuvash language written in the Cyrillic script.
+
 
 * Changes in Specialized Modes and Packages in Emacs 29.1
 
@@ -1752,10 +1785,9 @@ the second one will switch to the "*Completions*" buffer.
 
 ---
 *** New user option 'completion-auto-wrap'.
-When non-nil, the commands 'next-completion', 'previous-completion',
-'next-line-completion' and 'previous-line-completion' automatically
-wrap around on reaching the beginning or the end of the "*Completions*"
-buffer.
+When non-nil, the commands 'next-completion' and 'previous-completion'
+automatically wrap around on reaching the beginning or the end of
+the "*Completions*" buffer.
 
 +++
 *** New values for the 'completion-auto-help' user option.
@@ -1996,6 +2028,26 @@ It narrows to the current node.
 
 ** EUDC
 
++++
+*** Deprecations planned for next release.
+After Emacs 29.1, some aspects of EUDC will be deprecated.  The goal
+of these deprecations is to simplify EUDC server configuration by
+making 'eudc-server-hotlist' the only place to add servers.  There
+will not be a need to set the server using the 'eudc-set-server'
+command.  Instead, the 'eudc-server-hotlist' user option should be
+customized to have an entry for the server.  The plan is to obsolete
+the 'eudc-hotlist' package since Customize is sufficient for changing
+'eudc-server-hotlist'.  How the 'eudc-server' user option works in this
+context is to-be-determined; it can't be removed, because that would
+break compatibility, but it may become synchronized with
+'eudc-server-hotlist' so that 'eudc-server' is always equal to '(car
+eudc-server-hotlist)'.  The first entry in 'eudc-server-hotlist' is the
+first server tried by 'eudc-expand-try-all'.  The hotlist
+simplification will allow 'eudc-query-form' to show a drop down of
+possible servers, instead of requiring a call to 'eudc-set-server'
+like it does in this release.  The default value of
+'eudc-ignore-options-file' will be changed from nil to t.
+
 +++
 *** New user option 'eudc-ignore-options-file' that defaults to nil.
 The 'eudc-ignore-options-file' user option can be configured to ignore
@@ -2706,6 +2758,9 @@ project-dedicated or global) is specified by the new
 ---
 *** New user option 'ruby-toggle-block-space-before-parameters'.
 
+---
+*** Support for endless methods.
+
 ** Eshell
 
 +++
@@ -2942,6 +2997,13 @@ features, such as completion, documentation, error 
detection, etc.,
 based on data provided by language servers using the Language Server
 Protocol (LSP).
 
++++
+*** use-package: Declarative package configuration.
+use-package is shipped with Emacs.  It provides the 'use-package'
+macro, which allows you to isolate package configuration in your init
+file in a way that is declarative, tidy, and performance-oriented.
+See the new Info manual "(use-package) Top" for more.
+
 +++
 ** New commands 'image-crop' and 'image-cut'.
 These commands allow interactively cropping/cutting the image at
@@ -2986,64 +3048,147 @@ Emacs buffers, like indentation and the like.  The new 
ert function
 This is a lightweight variant of 'js-mode' that is used by default
 when visiting JSON files.
 
-** New major mode 'typescript-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the TypeScript language.  It includes support for font-locking,
-indentation, and navigation.  This mode will be auto-enabled for
-files with the '.ts' extension.
-
-** New major mode 'tsx-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the TypeScript language, with support for TSX.  It includes
-support for font-locking, indentation, and navigation.  This mode
-will be auto-enabled for files with the '.tsx' extension.
-
-** New major mode 'c-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the C language.  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
-** New major mode 'c++-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the C++ language.  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
-** New major mode 'java-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the Java language.  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
-** New major mode 'python-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the Python language.  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
-** New major mode 'css-ts-mode'.
-A major mode based on the tree-sitter library for editing CSS
-(Cascading Style Sheets).  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
-** New major mode 'json-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the JSON language.  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
-** New major mode 'csharp-ts-mode'.
-A major mode based on the tree-sitter library for editing programs
-in the C# language.  It includes support for font-locking,
-indentation, Imenu, which-func, and navigation.
-
 ** New major mode 'csharp-mode'.
 A major mode based on CC Mode for editing programs in the C# language.
+This mode is auto-enabled for files with the ".cs" extension.
+
+** New major modes based on the tree-sitter library.
+These new major modes are available if Emacs was built with the
+tree-sitter library.  They provide support for font-locking,
+indentation, and navigation by defuns based on parsing the buffer text
+by a tree-sitter parser.  Some major modes also offer support for
+Imenu and 'which-func'.
+
+Where major modes already exist in Emacs for editing certain kinds of
+files, the new modes based on tree-sitter are for now entirely
+optional, and you must turn them on manually, or customize
+'auto-mode-alist' to turn them on automatically.
+
+Each major mode based on tree-sitter needs a language grammar library,
+usually named "libtree-sitter-LANG.so" ("libtree-sitter-LANG.dll" on
+MS-Windows), where LANG is the corresponding language name.  Emacs
+looks for these libraries in the following places:
+
+ . in the directories mentioned in the list 'treesit-extra-load-path'
+ . in the "tree-sitter" subdirectory of your 'user-emacs-directory'
+   (by default, "~/.emacs.d/tree-sitter")
+ . in the standard system directories where other shared libraries are
+   usually installed
+
+We recommend to install these libraries in one of the standard system
+locations (the last place in the above list).
+
+If a language grammar library required by a mode is not found in any
+of the above places, the mode will signal an error when you try to
+turn it on.
+
+*** New major mode 'typescript-ts-mode'.
+A major mode based on the tree-sitter library for editing programs
+in the TypeScript language.  This mode is auto-enabled for files with
+the ".ts" extension.
 
-** New major mode 'bash-ts-mode'.
-A major mode based on the tree-sitter library for editing Bash shell
-scripts.  It includes support for font-locking, indentation, Imenu,
-which-func, and navigation.
+*** New major mode 'tsx-ts-mode'.
+A major mode based on the tree-sitter library for editing programs
+in the TypeScript language, with support for TSX.  This mode is
+auto-enabled for files with the ".tsx" extension.
+
+*** New major mode 'c-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+programs in the C language.
+
+*** New major mode 'c++-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+programs in the C++ language.
+
+*** New major mode 'java-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+programs in the Java language.
+
+*** New major mode 'python-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+programs in the Python language.
+
+*** New major mode 'css-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+CSS (Cascading Style Sheets).
+
+*** New major mode 'json-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+programs in the JSON language.
+
+*** New major mode 'csharp-ts-mode'.
+An optional major mode based on the tree-sitter library for editing
+programs in the C# language.
+
+*** New major mode 'bash-ts-mode'.
+Am optional major mode based on the tree-sitter library for editing
+Bash shell scripts.
+
+*** New major mode 'dockerfile-ts-mode'.
+A major mode based on the tree-sitter library for editing
+Dockerfiles.  This mode is auto-enabled for files which are named
+"Dockerfile", have the "Dockerfile." prefix, or have the ".dockerfile"
+extension.
+
+*** New major mode 'cmake-ts-mode'.
+A major mode based on the tree-sitter library for editing CMake files.
+It is auto-enabled for files whose name is "CMakeLists.txt" or whose
+extension is ".cmake".
+
+*** New major mode 'toml-ts-mode'.
+A major mode based on the tree-sitter library for editing files
+written in TOML, a format for writing configuration files.  It is
+auto-enabled for files with the ".toml" extension.
+
+*** New major mode 'go-ts-mode'.
+A major mode based on the tree-sitter library for editing programs in
+the Go language.  It is auto-enabled for files with the ".go" extension.
+
+*** New major mode 'go-mod-ts-mode'.
+A major mode based on the tree-sitter library for editing "go.mod"
+files.  It is auto-enabled for files which are named "go.mod".
+
+*** New major mode 'yaml-ts-mode'.
+A major mode based on the tree-sitter library for editing files
+written in YAML.  It is auto-enabled for files with the ".yaml" or
+".yml" extensions.
+
+*** New major mode 'rust-ts-mode'.
+A major mode based on the tree-sitter library for editing programs in
+the Rust language.  It is auto-enabled for files with the ".rs" extension.
 
 
 * Incompatible Lisp Changes in Emacs 29.1
 
++++
+** The implementation of overlays has changed.
+Emacs now uses an implementation of overlays that is much more
+efficient than the original one, and should speed up all the
+operations that involve overlays, especially when there are lots of
+them in a buffer.
+
+As result of this, some minor incompatibilities in behavior could be
+observed, as described below.  Except those minor incompatibilities,
+no other changes in behavior of overlays should be visible on the Lisp
+or user level, with the exception of better performance and the order
+of overlays returned by functions that don't promise any particular
+order.
+
+*** The function 'overlay-recenter' is now a no-op.
+This function does nothing, and in particular has no effect on the
+value returned by 'overlay-lists'.  The purpose of 'overlay-recenter'
+was to allow more efficient lookup of overlays around certain buffer
+position; however with the new implementation the lookup of overlays
+is efficient regardless of their position, and there's no longer any
+need to "optimize" the lookup, nor any notion of "center" of the
+overlays.
+
+*** The function 'overlay-lists' returns one unified list of overlays.
+This function used to return a cons of two lists, one with overlays
+before the "center" position, the other after that "center".  It now
+returns a list whose 'car' is the list of all the buffer overlays, and
+whose 'cdr' is always nil.
+
 +++
 ** 'format-prompt' now uses 'substitute-command-keys'.
 This means that both the prompt and 'minibuffer-default-prompt-format'
@@ -4387,6 +4532,23 @@ Now 'max-lisp-eval-depth' alone is used for limiting 
Lisp recursion
 and stack usage.  'max-specpdl-size' is still present as a plain
 variable for compatibility but its limiting powers have been taken away.
 
+** New function 'external-completion-table'.
+This function returns a completion table designed to ease
+communication between Emacs's completion facilities and external tools
+offering completion services, particularly tools whose full working
+set is too big to transfer to Emacs every time a completion is
+needed.  The table uses new 'external' completion style exclusively
+and cannot work with regular styles such as 'basic' or 'flex'.
+
++++
+** Magic file name handlers for 'make-directory-internal' are no longer needed.
+Instead, Emacs uses the already-existing 'make-directory' handlers.
+
++++
+** '(make-directory DIR t)' returns non-nil if DIR already exists.
+This can let a caller know whether it created DIR.  Formerly,
+'make-directory's return value was unspecified.
+
 
 * Changes in Emacs 29.1 on Non-Free Operating Systems
 
diff --git a/etc/PROBLEMS b/etc/PROBLEMS
index 2169ed0f80..f114049985 100644
--- a/etc/PROBLEMS
+++ b/etc/PROBLEMS
@@ -1227,6 +1227,20 @@ you should use an Emacs input method instead.
 
 * X runtime problems
 
+** X security problems
+
+*** Emacs faces trouble when running as an untrusted client.
+
+When Emacs is running as an untrusted client under X servers with the
+Security extension, it is unable to use some window manager features
+but reports them to the window manager anyway.  This can lead to
+constant prompting by the window manager about Emacs being
+unresponsive.  To resolve the problem, place:
+
+  (setq x-detect-server-trust t)
+
+in your early-init.el.
+
 ** X keyboard problems
 
 *** `x-focus-frame' fails to activate the frame.
@@ -1698,8 +1712,8 @@ which can be carried out at the same time:
 
 7) If selecting text with the mouse is slow, the main culprit is
    likely `select-active-regions', coupled with a program monitoring
-   the clipboard on the X server you are connected to.  Try turning
-   that off.
+   the clipboard or primary selection on the X server you are
+   connected to.  Try turning that off.
 
    However, over networks with moderate to high latency, with no
    clipboard monitor running, the bottleneck is likely to be
@@ -1709,6 +1723,12 @@ which can be carried out at the same time:
    cause Emacs features that relies on accurate mouse position
    reporting to stop working reliably.
 
+8) If creating or resizing frames is slow, turn off
+   `frame-resize-pixelwise' (this will not take effect until you
+   create a new frame); then, enable `x-lax-frame-positioning'.  This
+   means frame placement will be less accurate, but makes frame
+   creation, movement, and resize visibly faster.
+
 *** Emacs gives the error, Couldn't find per display information.
 
 This can result if the X server runs out of memory because Emacs uses
diff --git a/lib-src/etags.c b/lib-src/etags.c
index d1d20858cd..280b5b9df2 100644
--- a/lib-src/etags.c
+++ b/lib-src/etags.c
@@ -401,6 +401,9 @@ static void invalidate_nodes (fdesc *, node **);
 static void put_entries (node *);
 static void cleanup_tags_file (char const * const, char const * const);
 
+#if !MSDOS && !defined (DOS_NT)
+static char *escape_shell_arg_string (char *);
+#endif
 static void do_move_file (const char *, const char *);
 static char *concat (const char *, const char *, const char *);
 static char *skip_spaces (char *);
@@ -1413,7 +1416,7 @@ main (int argc, char **argv)
           setenv ("LC_COLLATE", "C", 1);
           setenv ("LC_ALL", "C", 1); */
        char *cmd = xmalloc (8 * strlen (tagfile) + sizeof "sort -u -o '' ''");
-#if defined WINDOWSNT || defined MSDOS
+#if defined WINDOWSNT || MSDOS
        /* Quote "like this".  No need to escape the quotes in the file name,
           since it is not allowed in file names on these systems.  */
        char *z = stpcpy (cmd, "sort -u -o \"");
@@ -1713,13 +1716,23 @@ process_file_name (char *file, language *lang)
       else
        {
 #if MSDOS || defined (DOS_NT)
-         char *cmd1 = concat (compr->command, " \"", real_name);
-         char *cmd = concat (cmd1, "\" > ", tmp_name);
+         int buf_len =
+           strlen (compr->command)
+           + strlen (" \"\" > \"\"") + strlen (real_name)
+           + strlen (tmp_name) + 1;
+         char *cmd = xmalloc (buf_len);
+         snprintf (cmd, buf_len, "%s \"%s\" > \"%s\"",
+                   compr->command, real_name, tmp_name);
 #else
-         char *cmd1 = concat (compr->command, " '", real_name);
-         char *cmd = concat (cmd1, "' > ", tmp_name);
+         char *new_real_name = escape_shell_arg_string (real_name);
+         char *new_tmp_name = escape_shell_arg_string (tmp_name);
+         int buf_len =
+           strlen (compr->command) + strlen ("  > ") + strlen (new_real_name)
+           + strlen (new_tmp_name) + 1;
+         char *cmd = xmalloc (buf_len);
+         snprintf (cmd, buf_len, "%s %s > %s",
+                   compr->command, new_real_name, new_tmp_name);
 #endif
-         free (cmd1);
          inf = (system (cmd) == -1
                 ? NULL
                 : fopen (tmp_name, "r" FOPEN_BINARY));
@@ -7707,8 +7720,59 @@ etags_mktmp (void)
   return templt;
 }
 
+#if !MSDOS && !defined (DOS_NT)
+/*
+ * Add single quotes around a string, and escape any single quotes.
+ * Return a newly-allocated string.
+ *
+ * For example:
+ * escape_shell_arg_string ("test.txt")  => "'test.txt'"
+ * escape_shell_arg_string ("'test.txt") => "''\''test.txt'"
+ */
+static char *
+escape_shell_arg_string (char *str)
+{
+  char *p = str;
+  int need_space = 2;          /* ' at begin and end */
+
+  while (*p != '\0')
+    {
+      if (*p == '\'')
+       need_space += 4;        /* ' to '\'', length is 4 */
+      else
+       need_space++;
+
+      p++;
+    }
+
+  char *new_str = xnew (need_space + 1, char);
+  new_str[0] = '\'';
+  new_str[need_space-1] = '\'';
+
+  int i = 1;                   /* skip first byte */
+  p = str;
+  while (*p != '\0')
+    {
+      new_str[i] = *p;
+      if (*p == '\'')
+       {
+         new_str[i+1] = '\\';
+         new_str[i+2] = '\'';
+         new_str[i+3] = '\'';
+         i += 3;
+       }
+
+      i++;
+      p++;
+    }
+
+  new_str[need_space] = '\0';
+  return new_str;
+}
+#endif
+
 static void
-do_move_file(const char *src_file, const char *dst_file)
+do_move_file (const char *src_file, const char *dst_file)
 {
   if (rename (src_file, dst_file) == 0)
     return;
diff --git a/lib-src/seccomp-filter.c b/lib-src/seccomp-filter.c
index 7e54b878a2..69b56aed5c 100644
--- a/lib-src/seccomp-filter.c
+++ b/lib-src/seccomp-filter.c
@@ -342,6 +342,8 @@ main (int argc, char **argv)
   RULE (SCMP_ACT_ALLOW, SCMP_SYS (eventfd2));
   RULE (SCMP_ACT_ALLOW, SCMP_SYS (wait4));
   RULE (SCMP_ACT_ALLOW, SCMP_SYS (poll));
+  RULE (SCMP_ACT_ALLOW, SCMP_SYS (pidfd_open),
+       SCMP_A1_32 (SCMP_CMP_EQ, 0));
 
   /* Don't allow creating sockets (network access would be extremely
      dangerous), but also don't crash.  */
diff --git a/lib/explicit_bzero.c b/lib/explicit_bzero.c
deleted file mode 100644
index ad0bfd170c..0000000000
--- a/lib/explicit_bzero.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/* Erasure of sensitive data, generic implementation.
-   Copyright (C) 2016-2022 Free Software Foundation, Inc.
-   This file is part of the GNU C Library.
-
-   The GNU C Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Lesser General Public
-   License as published by the Free Software Foundation; either
-   version 2.1 of the License, or (at your option) any later version.
-
-   The GNU C Library 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
-   Lesser General Public License for more details.
-
-   You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library; if not, see
-   <https://www.gnu.org/licenses/>.  */
-
-/* An assembler implementation of explicit_bzero can be created as an
-   assembler alias of an optimized bzero implementation.
-   Architecture-specific implementations also need to define
-   __explicit_bzero_chk.  */
-
-#if !_LIBC
-# include <config.h>
-#endif
-
-/* memset_s need this define */
-#if HAVE_MEMSET_S
-# define __STDC_WANT_LIB_EXT1__ 1
-#endif
-
-#include <string.h>
-
-#if defined _WIN32 && !defined __CYGWIN__
-# define  WIN32_LEAN_AND_MEAN
-# include <windows.h>
-#endif
-
-#if _LIBC
-/* glibc-internal users use __explicit_bzero_chk, and explicit_bzero
-   redirects to that.  */
-# undef explicit_bzero
-#endif
-
-/* Set LEN bytes of S to 0.  The compiler will not delete a call to
-   this function, even if S is dead after the call.  */
-void
-explicit_bzero (void *s, size_t len)
-{
-#if defined _WIN32 && !defined __CYGWIN__
-  (void) SecureZeroMemory (s, len);
-#elif HAVE_EXPLICIT_MEMSET
-  explicit_memset (s, '\0', len);
-#elif HAVE_MEMSET_S
-  (void) memset_s (s, len, '\0', len);
-#elif defined __GNUC__ && !defined __clang__
-  memset (s, '\0', len);
-  /* Compiler barrier.  */
-  asm volatile ("" ::: "memory");
-#elif defined __clang__
-  memset (s, '\0', len);
-  /* Compiler barrier.  */
-  /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that the
-     whole thing is dead and eliminates it.  Use 'g' to work around this
-     problem.  See <https://bugs.llvm.org/show_bug.cgi?id=15495#c11>.  */
-  __asm__ volatile ("" : : "g"(s) : "memory");
-#else
-  /* Invoke memset through a volatile function pointer.  This defeats compiler
-     optimizations.  */
-  void * (* const volatile volatile_memset) (void *, int, size_t) = memset;
-  (void) volatile_memset (s, '\0', len);
-#endif
-}
diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in
index 9af8fd0c57..fcbf5bde2d 100644
--- a/lib/gnulib.mk.in
+++ b/lib/gnulib.mk.in
@@ -93,7 +93,6 @@
 #  dup2 \
 #  environ \
 #  execinfo \
-#  explicit_bzero \
 #  faccessat \
 #  fchmodat \
 #  fcntl \
@@ -126,6 +125,7 @@
 #  memmem-simple \
 #  mempcpy \
 #  memrchr \
+#  memset_explicit \
 #  minmax \
 #  mkostemp \
 #  mktime \
@@ -264,7 +264,6 @@ GL_COND_OBJ_DIRFD_CONDITION = @GL_COND_OBJ_DIRFD_CONDITION@
 GL_COND_OBJ_DUP2_CONDITION = @GL_COND_OBJ_DUP2_CONDITION@
 GL_COND_OBJ_EUIDACCESS_CONDITION = @GL_COND_OBJ_EUIDACCESS_CONDITION@
 GL_COND_OBJ_EXECINFO_CONDITION = @GL_COND_OBJ_EXECINFO_CONDITION@
-GL_COND_OBJ_EXPLICIT_BZERO_CONDITION = @GL_COND_OBJ_EXPLICIT_BZERO_CONDITION@
 GL_COND_OBJ_FACCESSAT_CONDITION = @GL_COND_OBJ_FACCESSAT_CONDITION@
 GL_COND_OBJ_FCHMODAT_CONDITION = @GL_COND_OBJ_FCHMODAT_CONDITION@
 GL_COND_OBJ_FCNTL_CONDITION = @GL_COND_OBJ_FCNTL_CONDITION@
@@ -286,6 +285,7 @@ GL_COND_OBJ_LCHMOD_CONDITION = 
@GL_COND_OBJ_LCHMOD_CONDITION@
 GL_COND_OBJ_LSTAT_CONDITION = @GL_COND_OBJ_LSTAT_CONDITION@
 GL_COND_OBJ_MEMPCPY_CONDITION = @GL_COND_OBJ_MEMPCPY_CONDITION@
 GL_COND_OBJ_MEMRCHR_CONDITION = @GL_COND_OBJ_MEMRCHR_CONDITION@
+GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION = @GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION@
 GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION = @GL_COND_OBJ_MINI_GMP_GNULIB_CONDITION@
 GL_COND_OBJ_MKOSTEMP_CONDITION = @GL_COND_OBJ_MKOSTEMP_CONDITION@
 GL_COND_OBJ_NANOSLEEP_CONDITION = @GL_COND_OBJ_NANOSLEEP_CONDITION@
@@ -485,6 +485,7 @@ GL_GNULIB_MEMCHR = @GL_GNULIB_MEMCHR@
 GL_GNULIB_MEMMEM = @GL_GNULIB_MEMMEM@
 GL_GNULIB_MEMPCPY = @GL_GNULIB_MEMPCPY@
 GL_GNULIB_MEMRCHR = @GL_GNULIB_MEMRCHR@
+GL_GNULIB_MEMSET_EXPLICIT = @GL_GNULIB_MEMSET_EXPLICIT@
 GL_GNULIB_MKDIR = @GL_GNULIB_MKDIR@
 GL_GNULIB_MKDIRAT = @GL_GNULIB_MKDIRAT@
 GL_GNULIB_MKDTEMP = @GL_GNULIB_MKDTEMP@
@@ -749,6 +750,7 @@ HAVE_MAX_ALIGN_T = @HAVE_MAX_ALIGN_T@
 HAVE_MBSLEN = @HAVE_MBSLEN@
 HAVE_MBTOWC = @HAVE_MBTOWC@
 HAVE_MEMPCPY = @HAVE_MEMPCPY@
+HAVE_MEMSET_EXPLICIT = @HAVE_MEMSET_EXPLICIT@
 HAVE_MKDIRAT = @HAVE_MKDIRAT@
 HAVE_MKDTEMP = @HAVE_MKDTEMP@
 HAVE_MKFIFO = @HAVE_MKFIFO@
@@ -1857,16 +1859,6 @@ EXTRA_DIST += execinfo.in.h
 endif
 ## end   gnulib module execinfo
 
-## begin gnulib module explicit_bzero
-ifeq (,$(OMIT_GNULIB_MODULE_explicit_bzero))
-
-ifneq (,$(GL_COND_OBJ_EXPLICIT_BZERO_CONDITION))
-libgnu_a_SOURCES += explicit_bzero.c
-endif
-
-endif
-## end   gnulib module explicit_bzero
-
 ## begin gnulib module faccessat
 ifeq (,$(OMIT_GNULIB_MODULE_faccessat))
 
@@ -2536,6 +2528,16 @@ endif
 endif
 ## end   gnulib module memrchr
 
+## begin gnulib module memset_explicit
+ifeq (,$(OMIT_GNULIB_MODULE_memset_explicit))
+
+ifneq (,$(GL_COND_OBJ_MEMSET_EXPLICIT_CONDITION))
+libgnu_a_SOURCES += memset_explicit.c
+endif
+
+endif
+## end   gnulib module memset_explicit
+
 ## begin gnulib module minmax
 ifeq (,$(OMIT_GNULIB_MODULE_minmax))
 
@@ -3362,6 +3364,7 @@ string.h: string.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's/@''GNULIB_MEMMEM''@/$(GL_GNULIB_MEMMEM)/g' \
              -e 's/@''GNULIB_MEMPCPY''@/$(GL_GNULIB_MEMPCPY)/g' \
              -e 's/@''GNULIB_MEMRCHR''@/$(GL_GNULIB_MEMRCHR)/g' \
+             -e 
's/@''GNULIB_MEMSET_EXPLICIT''@/$(GL_GNULIB_MEMSET_EXPLICIT)/g' \
              -e 's/@''GNULIB_RAWMEMCHR''@/$(GL_GNULIB_RAWMEMCHR)/g' \
              -e 's/@''GNULIB_STPCPY''@/$(GL_GNULIB_STPCPY)/g' \
              -e 's/@''GNULIB_STPNCPY''@/$(GL_GNULIB_STPNCPY)/g' \
@@ -3393,6 +3396,7 @@ string.h: string.in.h $(top_builddir)/config.status 
$(CXXDEFS_H) $(ARG_NONNULL_H
              -e 's|@''HAVE_DECL_MEMMEM''@|$(HAVE_DECL_MEMMEM)|g' \
              -e 's|@''HAVE_MEMPCPY''@|$(HAVE_MEMPCPY)|g' \
              -e 's|@''HAVE_DECL_MEMRCHR''@|$(HAVE_DECL_MEMRCHR)|g' \
+             -e 's|@''HAVE_MEMSET_EXPLICIT''@|$(HAVE_MEMSET_EXPLICIT)|g' \
              -e 's|@''HAVE_RAWMEMCHR''@|$(HAVE_RAWMEMCHR)|g' \
              -e 's|@''HAVE_STPCPY''@|$(HAVE_STPCPY)|g' \
              -e 's|@''HAVE_STPNCPY''@|$(HAVE_STPNCPY)|g' \
diff --git a/lib/memset_explicit.c b/lib/memset_explicit.c
new file mode 100644
index 0000000000..eabeb3ec2b
--- /dev/null
+++ b/lib/memset_explicit.c
@@ -0,0 +1,55 @@
+/* Erase sensitive data from memory.
+   Copyright 2022 Free Software Foundation, Inc.
+
+   This file is free software: you can redistribute it and/or modify
+   it under the terms of the GNU Lesser General Public License as
+   published by the Free Software Foundation; either version 2.1 of the
+   License, or (at your option) any later version.
+
+   This file 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 Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public License
+   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+/* memset_s need this define */
+#if HAVE_MEMSET_S
+# define __STDC_WANT_LIB_EXT1__ 1
+#endif
+
+#include <string.h>
+
+/* Set S's bytes to C, where S has LEN bytes.  The compiler will not
+   optimize effects away, even if S is dead after the call.  */
+void *
+memset_explicit (void *s, int c, size_t len)
+{
+#if HAVE_EXPLICIT_MEMSET
+  return explicit_memset (s, c, len);
+#elif HAVE_MEMSET_S
+  (void) memset_s (s, len, c, len);
+  return s;
+#elif defined __GNUC__ && !defined __clang__
+  memset (s, c, len);
+  /* Compiler barrier.  */
+  __asm__ volatile ("" ::: "memory");
+  return s;
+#elif defined __clang__
+  memset (s, c, len);
+  /* Compiler barrier.  */
+  /* With asm ("" ::: "memory") LLVM analyzes uses of 's' and finds that the
+     whole thing is dead and eliminates it.  Use 'g' to work around this
+     problem.  See <https://bugs.llvm.org/show_bug.cgi?id=15495#c11>.  */
+  __asm__ volatile ("" : : "g"(s) : "memory");
+  return s;
+#else
+  /* Invoke memset through a volatile function pointer.  This defeats compiler
+     optimizations.  */
+  void * (* const volatile volatile_memset) (void *, int, size_t) = memset;
+  return volatile_memset (s, c, len);
+#endif
+}
diff --git a/lib/string.in.h b/lib/string.in.h
index e56f6db0c9..21356914e2 100644
--- a/lib/string.in.h
+++ b/lib/string.in.h
@@ -347,6 +347,23 @@ _GL_WARN_ON_USE (memrchr, "memrchr is unportable - "
 # endif
 #endif
 
+/* Overwrite a block of memory.  The compiler will not optimize
+   effects away, even if the block is dead after the call.  */
+#if @GNULIB_MEMSET_EXPLICIT@
+# if ! @HAVE_MEMSET_EXPLICIT@
+_GL_FUNCDECL_SYS (memset_explicit, void *,
+                  (void *__dest, int __c, size_t __n) _GL_ARG_NONNULL ((1)));
+# endif
+_GL_CXXALIAS_SYS (memset_explicit, void *, (void *__dest, int __c, size_t 
__n));
+_GL_CXXALIASWARN (memset_explicit);
+#elif defined GNULIB_POSIXCHECK
+# undef memset_explicit
+# if HAVE_RAW_DECL_MEMSET_EXPLICIT
+_GL_WARN_ON_USE (memset_explicit, "memset_explicit is unportable - "
+                 "use gnulib module memset_explicit for portability");
+# endif
+#endif
+
 /* Find the first occurrence of C in S.  More efficient than
    memchr(S,C,N), at the expense of undefined behavior if C does not
    occur within N bytes.  */
diff --git a/lib/verify.h b/lib/verify.h
index 99af802993..5225a8e616 100644
--- a/lib/verify.h
+++ b/lib/verify.h
@@ -37,7 +37,7 @@
           && (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || 5 <= __clang_major__)))
 #  define _GL_HAVE__STATIC_ASSERT 1
 # endif
-# if (202000 <= __STDC_VERSION__ \
+# if (202311 <= __STDC_VERSION__ \
       || (!defined __STRICT_ANSI__ && 9 <= __GNUC__))
 #  define _GL_HAVE__STATIC_ASSERT1 1
 # endif
diff --git a/lisp/ChangeLog.15 b/lisp/ChangeLog.15
index 8a21c291e7..ac1befac1e 100644
--- a/lisp/ChangeLog.15
+++ b/lisp/ChangeLog.15
@@ -10320,7 +10320,7 @@
        * bs.el, expand.el, ido.el, image-dired.el, lpr.el, pcomplete.el,
        * skeleton.el, term.el, time.el, wid-edit.el, woman.el,
        * calc/calc-graph.el, calc/calc-help.el, calc/calc-incom.el,
-       * calc/calc.el, emacs-lisp/cl-extra.el, emacs-lips/cl-loaddefs.el,
+       * calc/calc.el, emacs-lisp/cl-extra.el, emacs-lisp/cl-loaddefs.el,
        * emulation/cua-rect.el, emulation/viper-ex.el, eshell/esh-test.el,
        * eshell/eshell.el, gnus/gnus-uu.el, gnus/nndoc.el, gnus/nnrss.el,
        * gnus/rfc2047.el, gnus/utf7.el, international/utf-7.el,
diff --git a/lisp/ChangeLog.16 b/lisp/ChangeLog.16
index 1d7684be81..ef230bf9ed 100644
--- a/lisp/ChangeLog.16
+++ b/lisp/ChangeLog.16
@@ -4866,7 +4866,7 @@
 2012-10-12  Fabián Ezequiel Gallina  <fgallina@cuca>
 
        * progmodes/python.el (python-mode-map):
-       Replace subtitute-key-definition with proper command remapping.
+       Replace substitute-key-definition with proper command remapping.
        (python-nav--up-list): Fix behavior for blocks on the same level.
 
 2012-10-11  Stefan Monnier  <monnier@iro.umontreal.ca>
@@ -24325,7 +24325,7 @@
        Pass nil for `after-find-file-from-revert-buffer'.
 
        * saveplace.el (save-place-find-file-hook): Use new variable
-       `rever-buffer-in-progress-p', not `after-find-file-from-revert-buffer'.
+       `revert-buffer-in-progress-p', not `after-find-file-from-revert-buffer'.
 
 2011-04-06  Glenn Morris  <rgm@gnu.org>
 
diff --git a/lisp/ChangeLog.17 b/lisp/ChangeLog.17
index c494f43896..57620513e3 100644
--- a/lisp/ChangeLog.17
+++ b/lisp/ChangeLog.17
@@ -25522,7 +25522,7 @@
 
        * textmodes/ispell.el (ispell-add-per-file-word-list):
        Fix `flyspell-correct-word-before-point' error when accepting
-       words and `coment-padding' is an integer by using
+       words and `comment-padding' is an integer by using
        `comment-normalize-vars' (Bug #14214).
 
 2013-04-17  Fabián Ezequiel Gallina  <fgallina@gnu.org>
diff --git a/lisp/ansi-osc.el b/lisp/ansi-osc.el
index 9b7f586d16..23d0363865 100644
--- a/lisp/ansi-osc.el
+++ b/lisp/ansi-osc.el
@@ -7,18 +7,20 @@
 ;; Maintainer: emacs-devel@gnu.org
 ;; Keywords: processes, terminals, services
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/lisp/apropos.el b/lisp/apropos.el
index a731926f45..89f1f150a1 100644
--- a/lisp/apropos.el
+++ b/lisp/apropos.el
@@ -496,7 +496,7 @@ Intended as a value for `revert-buffer-function'."
               outline-level (lambda () 1)
               outline-minor-mode-cycle t
               outline-minor-mode-highlight t
-              outline-minor-mode-use-buttons t))
+              outline-minor-mode-use-buttons 'insert))
 
 (defvar apropos-multi-type t
   "If non-nil, this apropos query concerns multiple types.
diff --git a/lisp/auth-source-pass.el b/lisp/auth-source-pass.el
index 74d3808448..fbb6944e26 100644
--- a/lisp/auth-source-pass.el
+++ b/lisp/auth-source-pass.el
@@ -111,12 +111,12 @@ HOSTS can be a string or a list of strings."
 (defun auth-source-pass--match-regexp (s)
   (rx-to-string ; autoloaded
    `(: (or bot "/")
-       (or (: (? (group-n 20 (+ (not (in ?\  ?/ ,s)))) "@")
-              (group-n 10 (+ (not (in ?\  ?/ ?@ ,s))))
-              (? ,s (group-n 30 (+ (not (in ?\  ?/ ,s))))))
-           (: (group-n 11 (+ (not (in ?\  ?/ ?@ ,s))))
-              (? ,s (group-n 31 (+ (not (in ?\  ?/ ,s)))))
-              (? "/" (group-n 21 (+ (not (in ?\  ?/ ,s)))))))
+       (or (: (? (group-n 20 (+ (not (in ?/ ,s)))) "@")     ; user prefix
+              (group-n 10 (+ (not (in ?/ ?@ ,s))))          ; host
+              (? ,s (group-n 30 (+ (not (in ?\s ?/ ,s)))))) ; port
+           (: (group-n 11 (+ (not (in ?/ ?@ ,s))))          ; host
+              (? ,s (group-n 31 (+ (not (in ?\s ?/ ,s)))))  ; port
+              (? "/" (group-n 21 (+ (not (in ?/ ,s)))))))   ; user suffix
        eot)
    'no-group))
 
diff --git a/lisp/bs.el b/lisp/bs.el
index 1fd31fb3b8..d6df89138d 100644
--- a/lisp/bs.el
+++ b/lisp/bs.el
@@ -157,15 +157,15 @@ HEADER         : String for header for first line or a 
function
                  which calculates column title.
 MINIMUM-LENGTH : Minimum width of column (number or name of function).
                  The function must return a positive integer.
-MAXIMUM-LENGTH : Maximum width of column (number or name of function)
-                 (currently ignored).
+MAXIMUM-LENGTH : Ignored.
 ALIGNMENT      : Alignment of column (`left', `right', `middle').
 FUN-OR-STRING  : Name of a function for calculating the value or a
                  string for a constant value.
 
-The function gets as parameter the buffer where we have started
-buffer selection and the list of all buffers to show.  The function must
-return a string representing the column's value."
+Functions for HEADER and MINIMUM-LENGTH are called with no arguments.
+FUN-OR-STRING gets as argument the buffer where we have started
+buffer selection and the list of all buffers to show.  The function
+must return a string representing the column's value."
   :group 'bs-appearance
   :type '(repeat sexp))
 
@@ -321,7 +321,7 @@ Must be a string used in `bs-configurations' for naming a 
configuration."
   :group 'bs-appearance
   :type 'string)
 
-(defcustom bs-string-show-normally  " "
+(defcustom bs-string-show-normally " "
   "String added in column 1 indicating an unmarked buffer."
   :group 'bs-appearance
   :type 'string)
@@ -384,12 +384,12 @@ don't highlight."
   "Define a new function for buffer sorting in Buffer Selection Menu.
 NAME specifies the sort order defined by function FUN.
 A value of nil for FUN means don't sort the buffer list.  Otherwise the
-functions must have two parameters - the buffers to compare.
+function must have two arguments - the buffers to compare.
 REGEXP-FOR-SORTING is a regular expression which describes the
 column title to highlight.
 FACE is a face used to fontify the sorted column title.  A value of nil means
 don't highlight.
-The new sort aspect will be inserted into list `bs-sort-functions'."
+The new sort aspect will be inserted into the list `bs-sort-functions'."
   (let ((tuple (assoc name bs-sort-functions)))
     (if tuple
         (setcdr tuple (list fun regexp-for-sorting face))
@@ -420,9 +420,6 @@ naming a sort behavior.  Default is \"by nothing\" which 
means no sorting."
 Non-nil means to show all buffers.  Otherwise show buffers
 defined by current configuration `bs-current-configuration'.")
 
-(defvar bs--window-config-coming-from nil
-  "Window configuration before starting Buffer Selection Menu.")
-
 (defvar bs--intern-show-never "^ \\|\\*buffer-selection\\*"
   "Regular expression specifying which buffers never to show.
 A buffer whose name matches this regular expression will never be
@@ -491,6 +488,23 @@ Used internally, only.")
   "<mouse-2>" #'bs-mouse-select
   "<mouse-3>" #'bs-mouse-select-other-frame)
 
+(defcustom bs-default-action-list '((display-buffer-reuse-window
+                                    display-buffer-below-selected)
+                                   (reusable-frames . nil)
+                                   (window-height . window-min-height))
+  "Default action list for showing the '*bs-selection*' buffer.
+
+This list will be passed to `pop-to-buffer' as its ACTION argument.
+It should be a cons cell (FUNCTIONS . ALIST), where FUNCTIONS is
+an action function or a list of action functions and ALIST is an
+action alist.  Each such action function should accept two
+arguments: a buffer to display and an alist of the same form as
+ALIST.  See `display-buffer' for details."
+  :type display-buffer--action-custom-type
+  :risky t
+  :version "30.1"
+  :group 'bs)
+
 ;; ----------------------------------------------------------------------
 ;; Functions
 ;; ----------------------------------------------------------------------
@@ -501,8 +515,8 @@ LIST is a list of buffers to test for appearance in Buffer 
Selection Menu.
 The result list depends on the global variables `bs-dont-show-regexp',
 `bs-must-show-regexp', `bs-dont-show-function', `bs-must-show-function'
 and `bs-buffer-sort-function'.
-If SORT-DESCRIPTION isn't nil the list will be sorted by
-a special function.  SORT-DESCRIPTION is an element of `bs-sort-functions'."
+If SORT-DESCRIPTION isn't nil the list will be sorted by a special
+function.  SORT-DESCRIPTION is an element of `bs-sort-functions'."
   (setq sort-description (or sort-description bs--current-sort-function)
        list (or list (buffer-list)))
   (let ((result nil))
@@ -568,9 +582,9 @@ SORT-DESCRIPTION is an element of `bs-sort-functions'."
     (beginning-of-line)))
 
 (defun bs--goto-current-buffer ()
-  "Goto line which represents the current buffer;
-actually the line which begins with character in `bs-string-current' or
-`bs-string-current-marked'."
+  "Go to line which represents the current buffer.
+Actually, it goes to the line which begins with the character
+in `bs-string-current' or `bs-string-current-marked'."
   (let ((regexp (concat "^"
                        (regexp-quote bs-string-current)
                        "\\|^"
@@ -590,21 +604,6 @@ actually the line which begins with character in 
`bs-string-current' or
     (format "Show buffer by configuration %S"
            bs-current-configuration)))
 
-(defun bs--track-window-changes (frame)
-  "Track window changes to refresh the buffer list.
-Used from `window-size-change-functions'."
-  (let ((win (get-buffer-window "*buffer-selection*" frame)))
-    (when win
-      (with-selected-window win
-       (bs--set-window-height)))))
-
-(defun bs--remove-hooks ()
-  "Remove `bs--track-window-changes' and auxiliary hooks."
-  (remove-hook 'window-size-change-functions 'bs--track-window-changes)
-  ;; Remove itself
-  (remove-hook 'kill-buffer-hook 'bs--remove-hooks t)
-  (remove-hook 'change-major-mode-hook 'bs--remove-hooks t))
-
 (put 'bs-mode 'mode-class 'special)
 
 (define-derived-mode bs-mode nil "Buffer-Selection-Menu"
@@ -663,25 +662,13 @@ apply it.
   (setq-local font-lock-defaults '(bs-mode-font-lock-keywords t))
   (setq-local font-lock-verbose nil)
   (setq-local font-lock-global-modes '(not bs-mode))
-  (setq-local revert-buffer-function 'bs-refresh)
-  (add-hook 'window-size-change-functions 'bs--track-window-changes)
-  (add-hook 'kill-buffer-hook 'bs--remove-hooks nil t)
-  (add-hook 'change-major-mode-hook 'bs--remove-hooks nil t))
-
-(defun bs--restore-window-config ()
-  "Restore window configuration on the current frame."
-  (when bs--window-config-coming-from
-    (let ((frame (selected-frame)))
-      (unwind-protect
-          (set-window-configuration bs--window-config-coming-from)
-       (select-frame frame)))
-    (setq bs--window-config-coming-from nil)))
+  (setq-local revert-buffer-function 'bs-refresh))
 
 (defun bs-kill ()
   "Let buffer disappear and reset window configuration."
   (interactive)
   (bury-buffer (current-buffer))
-  (bs--restore-window-config))
+  (quit-window))
 
 (defun bs-abort ()
   "Ding and leave Buffer Selection Menu without a selection."
@@ -705,7 +692,9 @@ Arguments are IGNORED (for `revert-buffer')."
 (defun bs--set-window-height ()
   "Change the height of the selected window to suit the current buffer list."
   (unless (one-window-p t)
-    (fit-window-to-buffer (selected-window) bs-max-window-height)))
+    (fit-window-to-buffer (selected-window) bs-max-window-height nil nil nil
+                         ;; preserve-size
+                         t)))
 
 (defun bs--current-buffer ()
   "Return buffer on current line.
@@ -742,7 +731,7 @@ Leave Buffer Selection Menu."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (bury-buffer (current-buffer))
-    (bs--restore-window-config)
+    (quit-window)
     (switch-to-buffer buffer)
     (when bs--marked-buffers
       ;; Some marked buffers for selection
@@ -765,7 +754,7 @@ Leave Buffer Selection Menu."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (bury-buffer (current-buffer))
-    (bs--restore-window-config)
+    (quit-window)
     (switch-to-buffer-other-window buffer)))
 
 (defun bs-tmp-select-other-window ()
@@ -781,7 +770,7 @@ Leave Buffer Selection Menu."
   (interactive)
   (let ((buffer (bs--current-buffer)))
     (bury-buffer (current-buffer))
-    (bs--restore-window-config)
+    (quit-window)
     (switch-to-buffer-other-frame buffer)))
 
 (defun bs-mouse-select-other-frame (event)
@@ -847,9 +836,8 @@ See `visit-tags-table'."
 
 (defun bs-set-current-buffer-to-show-always (&optional not-to-show-p)
   "Toggle status of buffer on line to `always shown'.
-NOT-TO-SHOW-P: prefix argument.
-With no prefix argument the buffer on current line is marked to show
-always.  Otherwise it is marked to show never."
+With prefix argument NOT-TO-SHOW-P, the buffer on current line
+is marked to never show instead."
   (interactive "P")
   (if not-to-show-p
       (bs-set-current-buffer-to-show-never)
@@ -1166,7 +1154,18 @@ Select buffer *buffer-selection* and display buffers 
according to current
 configuration `bs-current-configuration'.  Set window height, fontify buffer
 and move point to current buffer."
   (setq bs-current-list list)
-  (switch-to-buffer (get-buffer-create "*buffer-selection*"))
+  (let* ((window-combination-limit 'window-size)
+        (bs-buf (get-buffer-create "*buffer-selection*"))
+        (bs-win (progn
+                  (pop-to-buffer bs-buf bs-default-action-list)
+                  (selected-window))))
+    ;; Delete other windows showing *buffer-selection*.
+    ;; Done after pop-to-buffer, instead of just calling delete-windows-on,
+    ;; to allow display-buffer-reuse(-mode)?-window to be used in ALIST.
+    (dolist (w (get-buffer-window-list bs-buf 'not t))
+      (unless (eq w bs-win)
+       (with-demoted-errors "Error deleting window: %S"
+         (delete-window w)))))
   (bs-mode)
   (let* ((inhibit-read-only t)
         (map-fun (lambda (entry)
@@ -1247,8 +1246,6 @@ by buffer configuration `bs-cycle-configuration-name'."
                                        bs--cycle-list)))
              (next (car tuple))
              (cycle-list (cdr tuple)))
-        ;; We don't want the frame iconified if the only window in the frame
-        ;; happens to be dedicated.
         (bury-buffer (current-buffer))
        (switch-to-buffer next nil t)
        (setq bs--cycle-list (append (cdr cycle-list)
@@ -1349,11 +1346,11 @@ ALL-BUFFERS is the list of buffers appearing in Buffer 
Selection Menu."
               'help-echo "mouse-2: select this buffer, mouse-3: select in 
other frame"
               'mouse-face 'highlight))
 
-(defun bs--get-mode-name (start-buffer _all-buffers)
+(defun bs--get-mode-name (_start-buffer _all-buffers)
   "Return the name of mode of current buffer for Buffer Selection Menu.
 START-BUFFER is the buffer where we started buffer selection.
 ALL-BUFFERS is the list of buffers appearing in Buffer Selection Menu."
-  (format-mode-line mode-name nil nil start-buffer))
+  (format-mode-line mode-name nil nil nil))
 
 (defun bs--get-file-name (_start-buffer _all-buffers)
   "Return string for column `File' in Buffer Selection Menu.
@@ -1438,26 +1435,13 @@ for buffer selection."
       ;; Only when not in buffer *buffer-selection*
       ;; we have to set the buffer we started the command
       (setq bs--buffer-coming-from (current-buffer)))
-    (let ((liste (bs-buffer-list))
-         (active-window (get-window-with-predicate
-                         (lambda (w)
-                           (string= (buffer-name (window-buffer w))
-                                    "*buffer-selection*"))
-                         nil (selected-frame))))
-      (if active-window
-         (select-window active-window)
-       (bs--restore-window-config)
-       (setq bs--window-config-coming-from (current-window-configuration))
-       (when (> (window-height) 7)
-          ;; Errors would mess with the window configuration (bug#10882).
-          (ignore-errors (select-window (split-window-below)))))
-      (bs-show-in-buffer liste)
-      (bs-message-without-log "%s" (bs--current-config-message)))))
+    (bs-show-in-buffer (bs-buffer-list))
+    (bs-message-without-log "%s" (bs--current-config-message))))
 
 (defun bs--configuration-name-for-prefix-arg (prefix)
   "Convert prefix argument PREFIX to a name of a buffer configuration.
 If PREFIX is nil return `bs-default-configuration'.
-If PREFIX is an integer return PREFIX element of `bs-configurations'.
+If PREFIX is an integer return PREFIXth element of `bs-configurations'.
 Otherwise return `bs-alternative-configuration'."
   (cond ;; usually activation
    ((null prefix)
diff --git a/lisp/buff-menu.el b/lisp/buff-menu.el
index 588fe599a4..448a5395c0 100644
--- a/lisp/buff-menu.el
+++ b/lisp/buff-menu.el
@@ -107,6 +107,9 @@ The value should be a function of one argument; it will be
 called with the buffer.  If this function returns non-nil,
 then the buffer will be displayed in the buffer list.")
 
+(defvar-local Buffer-menu-buffer-list nil
+  "The current list of buffers or function to return buffers.")
+
 (defvar-keymap Buffer-menu-mode-map
   :doc "Local keymap for `Buffer-menu-mode' buffers."
   :parent tabulated-list-mode-map
@@ -628,8 +631,10 @@ This behaves like invoking \\[read-only-mode] in that 
buffer."
 This is called by `buffer-menu' and others as a subroutine.
 
 If FILES-ONLY is non-nil, show only file-visiting buffers.
-If BUFFER-LIST is non-nil, it should be a list of buffers; it
-means list those buffers and no others.
+If BUFFER-LIST is non-nil, it should be either a list of buffers
+or a function that returns a list of buffers; it means
+list those buffers and no others.
+See more at `Buffer-menu-buffer-list'.
 If FILTER-PREDICATE is non-nil, it should be a function
 that filters out buffers from the list of buffers.
 See more at `Buffer-menu-filter-predicate'."
@@ -639,6 +644,7 @@ See more at `Buffer-menu-filter-predicate'."
       (Buffer-menu-mode)
       (setq Buffer-menu-files-only
            (and files-only (>= (prefix-numeric-value files-only) 0)))
+      (setq Buffer-menu-buffer-list buffer-list)
       (setq Buffer-menu-filter-predicate filter-predicate)
       (list-buffers--refresh buffer-list old-buffer)
       (tabulated-list-print))
@@ -665,9 +671,16 @@ See more at `Buffer-menu-filter-predicate'."
                               Buffer-menu-filter-predicate))
        entries name-width)
     ;; Collect info for each buffer we're interested in.
-    (dolist (buffer (or buffer-list
-                       (buffer-list (if Buffer-menu-use-frame-buffer-list
-                                        (selected-frame)))))
+    (dolist (buffer (cond
+                     ((functionp buffer-list)
+                      (funcall buffer-list))
+                     (buffer-list)
+                     ((functionp Buffer-menu-buffer-list)
+                      (funcall Buffer-menu-buffer-list))
+                     (Buffer-menu-buffer-list)
+                     (t (buffer-list
+                         (if Buffer-menu-use-frame-buffer-list
+                             (selected-frame))))))
       (with-current-buffer buffer
        (let* ((name (buffer-name))
               (file buffer-file-name))
diff --git a/lisp/calc/calc-units.el b/lisp/calc/calc-units.el
index 42156b9460..cc1f5085a7 100644
--- a/lisp/calc/calc-units.el
+++ b/lisp/calc/calc-units.el
@@ -319,28 +319,28 @@ that the combined units table will be rebuilt.")
 (defvar math-unit-prefixes
   '( ( ?Q  (^ 10 30)  "quetta"  )
      ( ?R  (^ 10 27)  "ronna"  )
-     ( ?Y  (^ 10 24)  "Yotta"  )
-     ( ?Z  (^ 10 21)  "Zetta"  )
-     ( ?E  (^ 10 18)  "Exa"    )
-     ( ?P  (^ 10 15)  "Peta"   )
-     ( ?T  (^ 10 12)  "Tera"   )
-     ( ?G  (^ 10 9)   "Giga"   )
-     ( ?M  (^ 10 6)   "Mega"   )
-     ( ?k  (^ 10 3)   "Kilo"   )
-     ( ?K  (^ 10 3)   "Kilo"   )
-     ( ?h  (^ 10 2)   "Hecto"  )
-     ( ?H  (^ 10 2)   "Hecto"  )
-     ( ?D  (^ 10 1)   "Deka"   )
+     ( ?Y  (^ 10 24)  "yotta"  )
+     ( ?Z  (^ 10 21)  "zetta"  )
+     ( ?E  (^ 10 18)  "exa"    )
+     ( ?P  (^ 10 15)  "peta"   )
+     ( ?T  (^ 10 12)  "tera"   )
+     ( ?G  (^ 10 9)   "giga"   )
+     ( ?M  (^ 10 6)   "mega"   )
+     ( ?k  (^ 10 3)   "kilo"   )
+     ( ?K  (^ 10 3)   "kilo"   )
+     ( ?h  (^ 10 2)   "hecto"  )
+     ( ?H  (^ 10 2)   "hecto"  )
+     ( ?D  (^ 10 1)   "deka"   )
      ( 0   (^ 10 0)    nil     )
-     ( ?d  (^ 10 -1)  "Deci"   )
-     ( ?c  (^ 10 -2)  "Centi"  )
-     ( ?m  (^ 10 -3)  "Milli"  )
-     ( ?u  (^ 10 -6)  "Micro"  )
-     ( ?μ  (^ 10 -6)  "Micro"  )
-     ( ?n  (^ 10 -9)  "Nano"   )
-     ( ?p  (^ 10 -12) "Pico"   )
-     ( ?f  (^ 10 -15) "Femto"  )
-     ( ?a  (^ 10 -18) "Atto"   )
+     ( ?d  (^ 10 -1)  "deci"   )
+     ( ?c  (^ 10 -2)  "centi"  )
+     ( ?m  (^ 10 -3)  "milli"  )
+     ( ?u  (^ 10 -6)  "micro"  )
+     ( ?μ  (^ 10 -6)  "micro"  )
+     ( ?n  (^ 10 -9)  "nano"   )
+     ( ?p  (^ 10 -12) "pico"   )
+     ( ?f  (^ 10 -15) "femto"  )
+     ( ?a  (^ 10 -18) "atto"   )
      ( ?z  (^ 10 -21) "zepto"  )
      ( ?y  (^ 10 -24) "yocto"  )
      ( ?r  (^ 10 -27) "ronto"  )
diff --git a/lisp/cedet/semantic/complete.el b/lisp/cedet/semantic/complete.el
index 00fe081acb..1f372804dc 100644
--- a/lisp/cedet/semantic/complete.el
+++ b/lisp/cedet/semantic/complete.el
@@ -1731,7 +1731,7 @@ Display mechanism using tooltip for a list of possible 
completions.")
       ;; Add any tail info.
       (setq msg (concat msg msg-tail))
       ;; Display tooltip.
-      (when (not (eq msg ""))
+      (when (not (equal msg ""))
        (semantic-displayer-tooltip-show msg)))))
 
 ;;; Compatibility
diff --git a/lisp/comint.el b/lisp/comint.el
index 4d9fc50187..7ba423e65d 100644
--- a/lisp/comint.el
+++ b/lisp/comint.el
@@ -384,7 +384,7 @@ This variable is buffer-local."
    "\\(?:\\(?:, try\\)? *again\\| (empty for no passphrase)\\| (again)\\)?"
    ;; "[[:alpha:]]" used to be "for", which fails to match non-English.
    "\\(?: [[:alpha:]]+ .+\\)?[[:blank:]]*[::៖][[:space:]]*\\'"
-   ;; The ccrypt encryption dialogue doesn't end with a colon, so
+   ;; The ccrypt encryption dialog doesn't end with a colon, so
    ;; treat it specially.
    "\\|^Enter encryption key: (repeat) *\\'"
    ;; openssh-8.6p1 format: "(user@host) Password:".
@@ -4121,9 +4121,15 @@ function called, or nil, if no function was called (if 
BEG = END)."
         (save-restriction
           (let ((beg2 beg1)
                 (end2 end1))
-            (when (= beg2 beg)
+            (when (and (= beg2 beg)
+                       (> beg2 (point-min))
+                       (eq is-output
+                           (eq (get-text-property (1- beg2) 'field) 'output)))
               (setq beg2 (field-beginning beg2)))
-            (when (= end2 end)
+            (when (and (= end2 end)
+                       (< end2 (point-max))
+                       (eq is-output
+                           (eq (get-text-property (1+ end2) 'field) 'output)))
               (setq end2 (field-end end2)))
             ;; Narrow to the whole field surrounding the region
             (narrow-to-region beg2 end2))
diff --git a/lisp/cus-edit.el b/lisp/cus-edit.el
index 94a9165453..8af4618dbd 100644
--- a/lisp/cus-edit.el
+++ b/lisp/cus-edit.el
@@ -1073,7 +1073,7 @@ plain variables.  This means that `setopt' will execute 
any
   ;; Check that the type is correct.
   (when-let ((type (get variable 'custom-type)))
     (unless (widget-apply (widget-convert type) :match value)
-      (user-error "Value `%S' does not match type %s" value type)))
+      (warn "Value `%S' does not match type %s" value type)))
   (put variable 'custom-check-value (list value))
   (funcall (or (get variable 'custom-set) #'set-default) variable value))
 
diff --git a/lisp/descr-text.el b/lisp/descr-text.el
index f2ffddcf70..f105f29244 100644
--- a/lisp/descr-text.el
+++ b/lisp/descr-text.el
@@ -366,7 +366,7 @@ This function is semi-obsolete.  Use 
`get-char-code-property'."
 ;; description is added to the category name as a tooltip
 (defsubst describe-char-categories (category-set)
   (let ((mnemonics (category-set-mnemonics category-set)))
-    (unless (eq mnemonics "")
+    (unless (equal mnemonics "")
       (list (mapconcat
             (lambda (x)
               (let* ((c (category-docstring x))
diff --git a/lisp/dired-aux.el b/lisp/dired-aux.el
index 5e1745069f..7499e590a0 100644
--- a/lisp/dired-aux.el
+++ b/lisp/dired-aux.el
@@ -1,7 +1,6 @@
 ;;; dired-aux.el --- less commonly used parts of dired -*- lexical-binding: t 
-*-
 
-;; Copyright (C) 1985-1986, 1992, 1994, 1998, 2000-2022 Free Software
-;; Foundation, Inc.
+;; Copyright (C) 1985-2022 Free Software Foundation, Inc.
 
 ;; Author: Sebastian Kremer <sk@thp.uni-koeln.de>.
 ;; Maintainer: emacs-devel@gnu.org
@@ -25,7 +24,7 @@
 
 ;;; Commentary:
 
-;; The parts of dired mode not normally used.  This is a space-saving hack
+;; The parts of Dired mode not normally used.  This is a space-saving hack
 ;; to avoid having to load a large mode when all that's wanted are a few
 ;; functions.
 
@@ -37,8 +36,6 @@
 ;;; Code:
 
 (require 'cl-lib)
-;; We need macros in dired.el to compile properly,
-;; and we call subroutines in it too.
 (require 'dired)
 
 (defvar dired-create-files-failures nil
@@ -135,7 +132,7 @@ substituted, and will be passed through normally to the 
shell.
 
 %s
 
-\(Press ^ to %s markers below these occurrences.)
+(Press ^ to %s markers below these occurrences.)
 "
    "`"
    (string (aref command (car char-positions)))
@@ -298,7 +295,7 @@ With prefix arg, prompt for argument SWITCHES which is 
options for `diff'."
 
 ;;;###autoload
 (defun dired-compare-directories (dir2 predicate)
-  "Mark files with different file attributes in two dired buffers.
+  "Mark files with different file attributes in two Dired buffers.
 Compare file attributes of files in the current directory
 with file attributes in directory DIR2 using PREDICATE on pairs of files
 with the same name.  Mark files for which PREDICATE returns non-nil.
@@ -312,8 +309,8 @@ PREDICATE is a Lisp expression that can refer to the 
following variables:
     fa1, fa2       - list of file attributes
                      returned by function `file-attributes'
 
-    where 1 refers to attribute of file in the current dired buffer
-    and 2 to attribute of file in second dired buffer.
+    where 1 refers to attribute of file in the current Dired buffer
+    and 2 to attribute of file in second Dired buffer.
 
 Examples of PREDICATE:
 
@@ -489,7 +486,8 @@ List has a form of (file-name full-file-name 
(attribute-list))."
 (defun dired-do-chmod (&optional arg)
   "Change the mode of the marked (or next ARG) files.
 Both octal numeric modes like `644' and symbolic modes like `g+w'
-are supported.  Type M-n to pull the file attributes of the file
+are supported.  Type \\<minibuffer-local-completion-map>\
+\\[next-history-element] to pull the file attributes of the file
 at point into the minibuffer.
 
 See Info node `(coreutils)File permissions' for more information.
@@ -538,7 +536,8 @@ has no effect on MS-Windows."
 ;;;###autoload
 (defun dired-do-chgrp (&optional arg)
   "Change the group of the marked (or next ARG) files.
-Type M-n to pull the file attributes of the file at point
+Type \\<minibuffer-local-completion-map>\\[next-history-element] \
+to pull the file attributes of the file at point
 into the minibuffer."
   (interactive "P")
   (if (and (memq system-type '(ms-dos windows-nt))
@@ -549,7 +548,8 @@ into the minibuffer."
 ;;;###autoload
 (defun dired-do-chown (&optional arg)
   "Change the owner of the marked (or next ARG) files.
-Type M-n to pull the file attributes of the file at point
+Type \\<minibuffer-local-completion-map>\\[next-history-element] \
+to pull the file attributes of the file at point
 into the minibuffer."
   (interactive "P")
   (if (and (memq system-type '(ms-dos windows-nt))
@@ -561,7 +561,8 @@ into the minibuffer."
 (defun dired-do-touch (&optional arg)
   "Change the timestamp of the marked (or next ARG) files.
 This calls touch.
-Type M-n to pull the file attributes of the file at point
+Type Type \\<minibuffer-local-completion-map>\\[next-history-element] \
+to pull the file attributes of the file at point
 into the minibuffer."
   (interactive "P")
   (dired-do-chxxx "Timestamp" dired-touch-program 'touch arg))
@@ -761,7 +762,7 @@ with a prefix argument."
 (defvar dired-aux-files)
 
 (defun dired-minibuffer-default-add-shell-commands ()
-  "Return a list of all commands associated with current dired files.
+  "Return a list of all commands associated with current Dired files.
 This function is used to add all related commands retrieved by `mailcap'
 to the end of the list of defaults just after the default value."
   (interactive)
@@ -774,7 +775,7 @@ to the end of the list of defaults just after the default 
value."
 
 ;; This is an extra function so that you can redefine it, e.g., to use gmhist.
 (defun dired-read-shell-command (prompt arg files)
-  "Read a dired shell command.
+  "Read a Dired shell command.
 PROMPT should be a format string with one \"%s\" format sequence,
 which is replaced by the value returned by `dired-mark-prompt',
 with ARG and FILES as its arguments.  FILES should be a list of
@@ -921,11 +922,11 @@ Also see the `dired-confirm-shell-command' variable."
 
 ;; Might use {,} for bash or csh:
 (defvar dired-mark-prefix ""
-  "Prepended to marked files in dired shell commands.")
+  "Prepended to marked files in Dired shell commands.")
 (defvar dired-mark-postfix ""
-  "Appended to marked files in dired shell commands.")
+  "Appended to marked files in Dired shell commands.")
 (defvar dired-mark-separator " "
-  "Separates marked files in dired shell commands.")
+  "Separates marked files in Dired shell commands.")
 
 (defun dired-shell-stuff-it (command file-list on-each &optional _raw-arg)
   ;; "Make up a shell command line from COMMAND and FILE-LIST.
@@ -1336,7 +1337,7 @@ See `dired-guess-shell-alist-user'."
 (defun dired-kill-line (&optional arg)
   "Kill the current line (not the files).
 With a prefix argument, kill that many lines starting with the current line.
-\(A negative argument kills backward.)"
+(A negative argument kills backward.)"
   (interactive "P")
   (setq arg (prefix-numeric-value arg))
   (let (buffer-read-only file)
@@ -1844,7 +1845,7 @@ See Info node `(emacs)Subdir switches' for more details."
     (message "Redisplaying...done")))
 
 (defun dired-reset-subdir-switches ()
-  "Set `dired-switches-alist' to nil and revert dired buffer."
+  "Set `dired-switches-alist' to nil and revert Dired buffer."
   (interactive)
   (setq dired-switches-alist nil)
   (revert-buffer))
@@ -1880,7 +1881,7 @@ See Info node `(emacs)Subdir switches' for more details."
 (defvar dired-omit-localp)
 
 (defun dired-add-entry (filename &optional marker-char relative)
-  "Add a new dired entry for FILENAME.
+  "Add a new Dired entry for FILENAME.
 Optionally mark it with MARKER-CHAR (a character, else uses
 `dired-marker-char').  Note that this adds the entry `out of order'
 if files are sorted by time, etc.
@@ -2008,7 +2009,7 @@ files matching `dired-omit-regexp'."
 
 ;;;###autoload
 (defun dired-remove-file (file)
-  "Remove entry FILE on each dired buffer.
+  "Remove entry FILE on each Dired buffer.
 Note this doesn't delete FILE in the file system.
 See `dired-delete-file' in case you wish that."
   (dired-fun-in-all-buffers
@@ -2107,7 +2108,7 @@ option are non-nil, renaming a directory named `old_name' 
to
 `new_name' does not exists already, it will be created and
 `old_name' be moved into it.  If only `new_name' (without the
 trailing /) is given or this option or
-`dired-create-destination-dirs' is `nil', `old_name' will be
+`dired-create-destination-dirs' is nil, `old_name' will be
 renamed to `new_name'."
   :type '(choice
           (const :tag
@@ -3077,7 +3078,7 @@ Type \\`SPC' or \\`y' to %s one file, \\`DEL' or \\`n' to 
skip to next,
 ;;;###autoload
 (defun dired-maybe-insert-subdir (dirname &optional
                                          switches no-error-if-not-dir-p)
-  "Insert this subdirectory into the same dired buffer.
+  "Insert this subdirectory into the same Dired buffer.
 If it is already present, just move to it (type \\[dired-do-redisplay] to 
refresh),
   else inserts it at its natural place (as `ls -lR' would have done).
 With a prefix arg, you may edit the ls switches used for this listing.
@@ -3427,7 +3428,7 @@ Lower levels are unaffected."
 
 ;;;###autoload
 (defun dired-tree-up (arg)
-  "Go up ARG levels in the dired tree."
+  "Go up ARG levels in the Dired tree."
   (interactive "p")
   (let ((dir (dired-current-directory)))
     (while (>= arg 1)
@@ -3439,7 +3440,7 @@ Lower levels are unaffected."
 
 ;;;###autoload
 (defun dired-tree-down ()
-  "Go down in the dired tree."
+  "Go down in the Dired tree."
   (interactive)
   (let ((dir (dired-current-directory)) ; has slash
        pos case-fold-search)           ; filenames are case sensitive
diff --git a/lisp/emacs-lisp/byte-opt.el b/lisp/emacs-lisp/byte-opt.el
index a7e1df3622..898dfffef6 100644
--- a/lisp/emacs-lisp/byte-opt.el
+++ b/lisp/emacs-lisp/byte-opt.el
@@ -755,7 +755,8 @@ for speeding up processing.")
                  ((eq head 'list) (cdr form))
                  ((memq head
                         ;; FIXME: Replace this list with a function property?
-                        '( length safe-length cons lambda
+                        '( lambda internal-make-closure
+                           length safe-length cons
                            string unibyte-string make-string concat
                            format format-message
                            substring substring-no-properties string-replace
@@ -1297,11 +1298,8 @@ See Info node `(elisp) Integer Basics'."
       (if else
           `(progn ,condition ,@else)
         condition))
-     ;; (if X nil t) -> (not X)
-     ((and (eq then nil) (eq else '(t)))
-      `(not ,condition))
-     ;; (if X t [nil]) -> (not (not X))
-     ((and (eq then t) (or (null else) (eq else '(nil))))
+     ;; (if X t) -> (not (not X))
+     ((and (eq then t) (null else))
       `(not ,(byte-opt--negate condition)))
      ;; (if VAR VAR X...) -> (or VAR (progn X...))
      ((and (symbolp condition) (eq condition then))
diff --git a/lisp/emacs-lisp/byte-run.el b/lisp/emacs-lisp/byte-run.el
index 1babf3ec2c..b5e887db83 100644
--- a/lisp/emacs-lisp/byte-run.el
+++ b/lisp/emacs-lisp/byte-run.el
@@ -653,7 +653,8 @@ types.  The types that can be suppressed with this macro are
 `suspicious'.
 
 For the `mapcar' case, only the `mapcar' function can be used in
-the symbol list.  For `suspicious', only `set-buffer' and `lsh' can be used."
+the symbol list.  For `suspicious', only `set-buffer', `lsh' and `eq'
+can be used."
   ;; Note: during compilation, this definition is overridden by the one in
   ;; byte-compile-initial-macro-environment.
   (declare (debug (sexp body)) (indent 1))
diff --git a/lisp/emacs-lisp/bytecomp.el b/lisp/emacs-lisp/bytecomp.el
index 3df983b367..6067800759 100644
--- a/lisp/emacs-lisp/bytecomp.el
+++ b/lisp/emacs-lisp/bytecomp.el
@@ -5488,6 +5488,83 @@ and corresponding effects."
            (eval form)
          form)))
 
+;; Check for (in)comparable constant values in calls to `eq', `memq' etc.
+
+(defun bytecomp--dodgy-eq-arg-p (x number-ok)
+  "Whether X is a bad argument to `eq' (or `eql' if NUMBER-OK is non-nil)."
+  (pcase x
+    ((or `(quote ,(pred consp)) `(function (lambda . ,_))) t)
+    ((or (pred consp) (pred symbolp)) nil)
+    ((pred integerp)
+     (not (or (<= -536870912 x 536870911) number-ok)))
+    ((pred floatp) (not number-ok))
+    (_ t)))
+
+(defun bytecomp--value-type-description (x)
+  (cond
+    ((proper-list-p x) "list")
+    ((recordp x) "record")
+    (t (symbol-name (type-of x)))))
+
+(defun bytecomp--arg-type-description (x)
+  (pcase x
+    (`(function (lambda . ,_)) "function")
+    (`(quote . ,val) (bytecomp--value-type-description val))
+    (_ (bytecomp--value-type-description x))))
+
+(defun bytecomp--warn-dodgy-eq-arg (form type parenthesis)
+  (macroexp-warn-and-return
+   (format "`%s' called with literal %s that may never match (%s)"
+           (car form) type parenthesis)
+   form '(suspicious eq) t))
+
+(defun bytecomp--check-eq-args (form &optional a b &rest _ignore)
+  (let* ((number-ok (eq (car form) 'eql))
+         (bad-arg (cond ((bytecomp--dodgy-eq-arg-p a number-ok) 1)
+                        ((bytecomp--dodgy-eq-arg-p b number-ok) 2))))
+    (if bad-arg
+        (bytecomp--warn-dodgy-eq-arg
+         form
+         (bytecomp--arg-type-description (nth bad-arg form))
+         (format "arg %d" bad-arg))
+      form)))
+
+(put 'eq  'compiler-macro #'bytecomp--check-eq-args)
+(put 'eql 'compiler-macro #'bytecomp--check-eq-args)
+
+(defun bytecomp--check-memq-args (form &optional elem list &rest _ignore)
+  (let* ((fn (car form))
+         (number-ok (eq fn 'memql)))
+    (cond
+     ((bytecomp--dodgy-eq-arg-p elem number-ok)
+      (bytecomp--warn-dodgy-eq-arg
+       form (bytecomp--arg-type-description elem) "arg 1"))
+     ((and (consp list) (eq (car list) 'quote)
+           (proper-list-p (cadr list)))
+      (named-let loop ((elts (cadr list)) (i 1))
+        (if elts
+            (let* ((elt (car elts))
+                   (x (cond ((eq fn 'assq) (car-safe elt))
+                            ((eq fn 'rassq) (cdr-safe elt))
+                            (t elt))))
+              (if (or (symbolp x)
+                      (and (integerp x)
+                           (or (<= -536870912 x 536870911) number-ok))
+                      (and (floatp x) number-ok))
+                  (loop (cdr elts) (1+ i))
+                (bytecomp--warn-dodgy-eq-arg
+                 form (bytecomp--value-type-description x)
+                 (format "element %d of arg 2" i))))
+          form)))
+     (t form))))
+
+(put 'memq  'compiler-macro #'bytecomp--check-memq-args)
+(put 'memql 'compiler-macro #'bytecomp--check-memq-args)
+(put 'assq  'compiler-macro #'bytecomp--check-memq-args)
+(put 'rassq 'compiler-macro #'bytecomp--check-memq-args)
+(put 'remq  'compiler-macro #'bytecomp--check-memq-args)
+(put 'delq  'compiler-macro #'bytecomp--check-memq-args)
+
 (provide 'byte-compile)
 (provide 'bytecomp)
 
diff --git a/lisp/emacs-lisp/checkdoc.el b/lisp/emacs-lisp/checkdoc.el
index 3bddb93b64..26d87a3622 100644
--- a/lisp/emacs-lisp/checkdoc.el
+++ b/lisp/emacs-lisp/checkdoc.el
@@ -22,28 +22,35 @@
 ;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
-;;
+
 ;;   The Emacs Lisp manual has a nice chapter on how to write
 ;; documentation strings.  Many stylistic suggestions are fairly
 ;; deterministic and easy to check for syntactically, but also easy
 ;; to forget.  The main checkdoc engine will perform the stylistic
 ;; checks needed to make sure these styles are remembered.
 ;;
-;; There are three ways to use checkdoc:
-;;   1) Use `flymake-mode'.
+;; There are four ways to use checkdoc:
+;;
+;;   1) Use `flymake-mode'.  Type `M-x flymake-mode' in any Emacs Lisp
+;;      buffer; the checkdoc back-end is enabled by default.
+;;
 ;;   2) Periodically use `checkdoc' or `checkdoc-current-buffer'.
-;;      `checkdoc' is a more interactive version of
-;;      `checkdoc-current-buffer'
+;;      The `checkdoc' command is a more interactive version of
+;;      `checkdoc-current-buffer'.
+;;
 ;;   3) Use `checkdoc-minor-mode' to automatically check your
 ;;      documentation whenever you evaluate Lisp code with C-M-x
 ;;      or [menu-bar emacs-lisp eval-buffer].  Additional key-bindings
 ;;      are also provided under C-c ? KEY
 ;;        (add-hook 'emacs-lisp-mode-hook 'checkdoc-minor-mode)
 ;;
+;;   4) Use `checkdoc-ispell' to spellcheck docstrings interactively.
+;;
 ;; Using `checkdoc':
 ;;
-;;   The commands `checkdoc' and `checkdoc-ispell' are the top-level
-;; entry points to all of the different checks that are available.  It
+;;   Most users will probably use checkdoc through `flymake'.  The
+;; commands `checkdoc' and `checkdoc-ispell' are the top-level entry
+;; points to all of the different checks that are available.  It
 ;; breaks examination of your Lisp file into four sections (comments,
 ;; documentation, messages, and spacing) and indicates its current
 ;; state in a status buffer.
@@ -66,7 +73,7 @@
 ;; interface offers several options, including the ability to skip to
 ;; the next error, or back up to previous errors.  Auto-fixing is
 ;; turned off at this stage, but you can use the `f' or `F' key to fix
-;; a given error (if the fix is available.)
+;; a given error (if the fix is available).
 ;;
 ;; Auto-fixing:
 ;;
@@ -99,6 +106,7 @@
 ;; install into Ispell on the fly, but only if Ispell is not already
 ;; running.  Use `ispell-kill-ispell' to make checkdoc restart it with
 ;; these words enabled.
+;;   See also the `flyspell-prog-mode' minor mode.
 ;;
 ;; Checking parameters:
 ;;
@@ -176,6 +184,7 @@
   "Support for doc string checking in Emacs Lisp."
   :prefix "checkdoc"
   :group 'lisp
+  :link '(emacs-commentary-link "checkdoc.el")
   :version "20.3")
 
 (defcustom checkdoc-minor-mode-string " CDoc"
diff --git a/lisp/emacs-lisp/cl-extra.el b/lisp/emacs-lisp/cl-extra.el
index 66b214554e..60b01051a3 100644
--- a/lisp/emacs-lisp/cl-extra.el
+++ b/lisp/emacs-lisp/cl-extra.el
@@ -552,7 +552,7 @@ too large if positive or too small if negative)."
                        ,new)))))
   (seq-subseq seq start end))
 
-;;; This isn't a defalias because autoloading defalises doesn't work
+;;; This isn't a defalias because autoloading defaliases doesn't work
 ;;; very well.
 
 ;;;###autoload
diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el
index 7b562aaa53..2c306d892c 100644
--- a/lisp/emacs-lisp/comp.el
+++ b/lisp/emacs-lisp/comp.el
@@ -4005,8 +4005,11 @@ display a message."
                              :command (list
                                        (expand-file-name invocation-name
                                                          invocation-directory)
-                                       "-no-comp-spawn" "--batch" "-l"
-                                       temp-file)
+                                       "-no-comp-spawn" "--batch"
+                                       "--eval"
+                                       ;; Suppress Abort dialogs on MS-Windows
+                                       "(setq w32-disable-abort-dialog t)"
+                                       "-l" temp-file)
                              :sentinel
                              (lambda (process _event)
                                (run-hook-with-args
diff --git a/lisp/emacs-lisp/gv.el b/lisp/emacs-lisp/gv.el
index 11251d7a96..48bc0269f3 100644
--- a/lisp/emacs-lisp/gv.el
+++ b/lisp/emacs-lisp/gv.el
@@ -417,9 +417,9 @@ The return value is the last VAL in the list.
   (lambda (do key alist &optional default remove testfn)
     (macroexp-let2 macroexp-copyable-p k key
       (gv-letplace (getter setter) alist
-        (macroexp-let2 nil p `(if (and ,testfn (not (eq ,testfn 'eq)))
-                                  (assoc ,k ,getter ,testfn)
-                                (assq ,k ,getter))
+        (macroexp-let2 nil p (if (member testfn '(nil 'eq #'eq))
+                                 `(assq ,k ,getter)
+                               `(assoc ,k ,getter ,testfn))
           (funcall do (if (null default) `(cdr ,p)
                         `(if ,p (cdr ,p) ,default))
                    (lambda (v)
diff --git a/lisp/emacs-lisp/macroexp.el b/lisp/emacs-lisp/macroexp.el
index abcb3e3e6b..e1902ca8e3 100644
--- a/lisp/emacs-lisp/macroexp.el
+++ b/lisp/emacs-lisp/macroexp.el
@@ -486,7 +486,7 @@ Assumes the caller has bound `macroexpand-all-environment'."
                          (setq form (macroexp--compiler-macro handler newform))
                          (if (eq newform form)
                              newform
-                           (macroexp--expand-all newform)))
+                           (macroexp--expand-all form)))
                      (macroexp--expand-all newform))))))
             (_ form))))
     (pop byte-compile-form-stack)))
diff --git a/lisp/emacs-lisp/oclosure.el b/lisp/emacs-lisp/oclosure.el
index a17fdb7e35..46bb02f5fb 100644
--- a/lisp/emacs-lisp/oclosure.el
+++ b/lisp/emacs-lisp/oclosure.el
@@ -4,18 +4,20 @@
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/lisp/emacs-lisp/package-vc.el b/lisp/emacs-lisp/package-vc.el
index a4520ab800..8f0eedd2f8 100644
--- a/lisp/emacs-lisp/package-vc.el
+++ b/lisp/emacs-lisp/package-vc.el
@@ -5,18 +5,20 @@
 ;; Author: Philip Kaludercic <philipk@posteo.net>
 ;; Keywords: tools
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -48,6 +50,7 @@
 (eval-when-compile (require 'rx))
 (eval-when-compile (require 'inline))
 (eval-when-compile (require 'map))
+(eval-when-compile (require 'cl-lib))
 (require 'package)
 (require 'lisp-mnt)
 (require 'vc)
@@ -291,21 +294,41 @@ asynchronously."
         (insert-file-contents main-file)
         (package-strip-rcs-id
          (or (lm-header "package-version")
-             (lm-header "version"))))
+             (lm-header "version")
+             "0")))
     "0"))
 
 (defun package-vc--main-file (pkg-desc)
   "Return the name of the main file for PKG-DESC."
   (cl-assert (package-vc-p pkg-desc))
-  (let ((pkg-spec (package-vc--desc->spec pkg-desc))
-        (name (symbol-name (package-desc-name pkg-desc))))
-    (or (plist-get pkg-spec :main-file)
-        (expand-file-name
-         (concat name ".el")
-         (file-name-concat
-          (or (package-desc-dir pkg-desc)
-              (expand-file-name name package-user-dir))
-          (plist-get pkg-spec :lisp-dir))))))
+  (let* ((pkg-spec (package-vc--desc->spec pkg-desc))
+         (name (symbol-name (package-desc-name pkg-desc)))
+         (directory (file-name-concat
+                     (or (package-desc-dir pkg-desc)
+                         (expand-file-name name package-user-dir))
+                     (plist-get pkg-spec :lisp-dir)))
+         (file (or (plist-get pkg-spec :main-file)
+                   (expand-file-name
+                    (concat name ".el")
+                    directory))))
+    (if (file-exists-p file) file
+      ;; The following heuristic is only necessary when fetching a
+      ;; repository with URL that would break the above assumptions.
+      ;; Concrete example: https://github.com/sachac/waveform-el does
+      ;; not have a file waveform-el.el, but a file waveform.el, so we
+      ;; try and find the closest match.
+      (let ((distance most-positive-fixnum) (best nil))
+        (dolist (alt (directory-files directory t "\\.el\\'" t))
+          (let ((sd (string-distance file alt)))
+            (when (and (not (string-match-p (rx (or (: "-autoloads.el")
+                                                    (: "-pkg.el"))
+                                                eos)
+                                            alt))
+                       (< sd distance))
+              (when (< sd distance)
+                (setq distance (string-distance file alt)
+                      best alt)))))
+        best))))
 
 (defun package-vc--generate-description-file (pkg-desc pkg-file)
   "Generate a package description file for PKG-DESC and write it to PKG-FILE."
@@ -464,6 +487,7 @@ documentation and marking the package as installed."
   (package--save-selected-packages
    (cons (package-desc-name pkg-desc)
          package-selected-packages))
+  (package--quickstart-maybe-refresh)
 
   ;; Confirm that the installation was successful
   (let ((main-file (package-vc--main-file pkg-desc)))
@@ -708,11 +732,11 @@ regular package, but it will not remove a VC package."
 (defun package-vc-checkout (pkg-desc directory &optional rev)
   "Clone the sources for PKG-DESC into DIRECTORY and visit that directory.
 Unlike `package-vc-install', this does not yet set up the package
-for use with Emacs; use `package-vc-link-directory' for setting
-the package up after this function finishes.
-Optional argument REV means to clone a specific version of the
-package; it defaults to the last version available from the
-package's repository.  If REV has the special value
+for use with Emacs; use `package-vc-install-from-checkout' for
+setting the package up after this function finishes.  Optional
+argument REV means to clone a specific version of the package; it
+defaults to the last version available from the package's
+repository.  If REV has the special value
 `:last-release' (interactively, the prefix argument), that stands
 for the last released version of the package."
   (interactive
@@ -751,10 +775,15 @@ name from the base name of DIR."
   (package-vc--archives-initialize)
   (let* ((name (or name (file-name-base (directory-file-name dir))))
          (pkg-dir (expand-file-name name package-user-dir)))
+    (when (file-exists-p pkg-dir)
+      (if (yes-or-no-p (format "Overwrite previous checkout for package `%s'?" 
name))
+          (package--delete-directory pkg-dir)
+        (error "There already exists a checkout for %s" name)))
     (make-symbolic-link (expand-file-name dir) pkg-dir)
     (package-vc--unpack-1
      (package-desc-create
       :name (intern name)
+      :dir pkg-dir
       :kind 'vc)
      (file-name-as-directory pkg-dir))))
 
diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el
index a9fd8c741e..1cc978923e 100644
--- a/lisp/emacs-lisp/package.el
+++ b/lisp/emacs-lisp/package.el
@@ -1949,8 +1949,10 @@ SEEN is used internally to detect infinite recursion."
               (if (eq next-pkg 'emacs)
                   (error "This package requires Emacs version %s"
                          (package-version-join next-version))
-                (error "Package `%s-%s' is unavailable"
-                       next-pkg (package-version-join next-version))))))
+                (error (if (not next-version)
+                           (format "Package `%s' is unavailable" next-pkg)
+                         (format "Package `%s' (version %s) is unavailable"
+                                 next-pkg (package-version-join 
next-version))))))))
           (setq packages
                 (package-compute-transaction (cons found packages)
                                              (package-desc-reqs found)
@@ -4560,6 +4562,7 @@ will be signaled in that case."
         (package--print-email-button maint)
         (string-trim (substring-no-properties (buffer-string))))))))
 
+;;;###autoload
 (defun package-report-bug (desc)
   "Prepare a message to send to the maintainers of a package.
 DESC must be a `package-desc' object."
diff --git a/lisp/emacs-lisp/rx.el b/lisp/emacs-lisp/rx.el
index ec51146484..f2a0dc5483 100644
--- a/lisp/emacs-lisp/rx.el
+++ b/lisp/emacs-lisp/rx.el
@@ -1152,7 +1152,12 @@ For extending the `rx' notation in FORM, use `rx-define' 
or `rx-let-eval'."
 
 (defun rx--to-expr (form)
   "Translate the rx-expression FORM to a Lisp expression yielding a regexp."
-  (let* ((rx--delayed-evaluation t)
+  (let* ((rx--local-definitions
+          ;; Retrieve local definitions from the macroexpansion environment.
+          ;; (It's unclear whether the previous value of 
`rx--local-definitions'
+          ;; should be included, and if so, in which order.)
+          (cdr (assq :rx-locals macroexpand-all-environment)))
+         (rx--delayed-evaluation t)
          (elems (car (rx--translate form)))
          (args nil))
     ;; Merge adjacent strings.
@@ -1282,12 +1287,7 @@ Additional constructs can be defined using `rx-define' 
and `rx-let',
 which see.
 
 \(fn REGEXPS...)"
-  ;; Retrieve local definitions from the macroexpansion environment.
-  ;; (It's unclear whether the previous value of `rx--local-definitions'
-  ;; should be included, and if so, in which order.)
-  (let ((rx--local-definitions
-         (cdr (assq :rx-locals macroexpand-all-environment))))
-    (rx--to-expr (cons 'seq regexps))))
+  (rx--to-expr (cons 'seq regexps)))
 
 (defun rx--make-binding (name tail)
   "Make a definitions entry out of TAIL.
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 8328324715..6704db3cc5 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -251,18 +251,17 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :eval (string-glyph-decompose "Å"))
   "Predicates for Strings"
   (string-equal
-   :eval (string-equal "foo" "foo"))
+   :eval (string-equal "abc" "abc")
+   :eval (string-equal "abc" "ABC"))
   (string-equal-ignore-case
    :eval (string-equal-ignore-case "foo" "FOO"))
-  (eq
-   :eval (eq "foo" "foo"))
-  (eql
-   :eval (eql "foo" "foo"))
   (equal
    :eval (equal "foo" "foo"))
   (cl-equalp
    :eval (cl-equalp "Foo" "foo"))
   (stringp
+   :eval (stringp "a")
+   :eval (stringp 'a)
    :eval "(stringp ?a)")
   (string-empty-p
    :no-manual t
@@ -271,16 +270,16 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :no-manual t
    :eval (string-blank-p " \n"))
   (string-lessp
-   :eval (string-lessp "foo" "bar")
+   :eval (string-lessp "abc" "def")
    :eval (string-lessp "pic4.png" "pic32.png")
-   :eval (string-lessp "1.1" "1 2"))
+   :eval (string-lessp "1.1" "1.2"))
   (string-greaterp
    :eval (string-greaterp "foo" "bar"))
   (string-version-lessp
    :eval (string-version-lessp "pic4.png" "pic32.png")
-   :eval (string-version-lessp "1.1" "1 2"))
+   :eval (string-version-lessp "1.9.3" "1.10.2"))
   (string-collate-lessp
-   :eval (string-collate-lessp "1.1" "1 2"))
+   :eval (string-collate-lessp "abc" "abd"))
   (string-prefix-p
    :eval (string-prefix-p "foo" "foobar"))
   (string-suffix-p
@@ -297,7 +296,8 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   "Converting Strings"
   (string-to-number
    :eval (string-to-number "42")
-   :eval (string-to-number "deadbeef" 16))
+   :eval (string-to-number "deadbeef" 16)
+   :eval (string-to-number "2.5e+03"))
   (number-to-string
    :eval (number-to-string 42))
   "Data About Strings"
@@ -627,8 +627,7 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (nconc
    :eval (nconc (list 1) (list 2 3 4)))
   (delq
-   :eval (delq 2 (list 1 2 3 4))
-   :eval (delq "a" (list "a" "b" "c" "d")))
+   :eval (delq 'a (list 'a 'b 'c 'd)))
   (delete
    :eval (delete 2 (list 1 2 3 4))
    :eval (delete "a" (list "a" "b" "c" "d")))
@@ -670,29 +669,25 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :eval (nlistp '(1 . 2)))
   "Finding Elements"
   (memq
-   :eval (memq 2 '(1 2 3))
-   :eval (memq 2.0 '(1.0 2.0 3.0))
-   :eval (memq "b" '("a" "b" "c")))
+   :eval (memq 'b '(a b c)))
+  (memql
+   :eval (memql 2.0 '(1.0 2.0 3.0)))
   (member
    :eval (member 2 '(1 2 3))
    :eval (member "b" '("a" "b" "c")))
   (remq
-   :eval (remq 2 '(1 2 3 2 4 2))
-   :eval (remq "b" '("a" "b" "c")))
-  (memql
-   :eval (memql 2.0 '(1.0 2.0 3.0)))
+   :eval (remq 'b '(a b c)))
   (member-ignore-case
    :eval (member-ignore-case "foo" '("bar" "Foo" "zot")))
   "Association Lists"
   (assoc
-   :eval (assoc 'b '((a 1) (b 2))))
+   :eval (assoc "b" '(("a" . 1) ("b" . 2))))
   (rassoc
-   :eval (rassoc '2 '((a . 1) (b . 2))))
+   :eval (rassoc "b" '((1 . "a") (2 . "b"))))
   (assq
-   :eval (assq 'b '((a 1) (b 2)))
-   :eval (assq "a" '(("a" 1) ("b" 2))))
+   :eval (assq 'b '((a . 1) (b . 2))))
   (rassq
-   :eval (rassq '2 '((a . 1) (b . 2))))
+   :eval (rassq 'b '((1 . a) (2 . b))))
   (assoc-string
    :eval (assoc-string "foo" '(("a" 1) (foo 2))))
   (alist-get
@@ -725,6 +720,88 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (safe-length
    :eval (safe-length '(a b c))))
 
+(define-short-documentation-group symbol
+  "Making symbols"
+  (intern
+   :eval (intern "abc"))
+  (intern-soft
+   :eval (intern-soft "Phooey!"))
+  (make-symbol
+   :eval (make-symbol "abc"))
+  "Comparing symbols"
+  (eq
+   :eval (eq 'abc 'abc)
+   :eval (eq 'abc 'abd))
+  (eql
+   :eval (eql 'abc 'abc))
+  (equal
+   :eval (equal 'abc 'abc))
+  "Name"
+  (symbol-name
+   :eval (symbol-name 'abc)))
+
+(define-short-documentation-group comparison
+  "General-purpose"
+  (eq
+   :eval (eq 'a 'a)
+   :eval "(eq ?A ?A)"
+   :eval (let ((x (list 'a "b" '(c) 4 5.0)))
+           (eq x x)))
+  (eql
+   :eval (eql 2 2)
+   :eval (eql 2.0 2.0)
+   :eval (eql 2.0 2))
+  (equal
+   :eval (equal "abc" "abc")
+   :eval (equal 2.0 2.0)
+   :eval (equal 2.0 2)
+   :eval (equal '(a "b" (c) 4.0) '(a "b" (c) 4.0)))
+  (cl-equalp
+   :eval (cl-equalp 2 2.0)
+   :eval (cl-equalp "ABC" "abc"))
+  "Numeric"
+  (=
+   :args (number &rest numbers)
+   :eval (= 2 2)
+   :eval (= 2.0 2.0)
+   :eval (= 2.0 2)
+   :eval (= 4 4 4 4))
+  (/=
+   :eval (/= 4 4))
+  (<
+   :args (number &rest numbers)
+   :eval (< 4 4)
+   :eval (< 1 2 3))
+  (<=
+   :args (number &rest numbers)
+   :eval (<= 4 4)
+   :eval (<= 1 2 2 3))
+  (>
+   :args (number &rest numbers)
+   :eval (> 4 4)
+   :eval (> 3 2 1))
+  (>=
+   :args (number &rest numbers)
+   :eval (>= 4 4)
+   :eval (>= 3 2 2 1))
+  "String"
+  (string-equal
+   :eval (string-equal "abc" "abc")
+   :eval (string-equal "abc" "ABC"))
+  (string-equal-ignore-case
+   :eval (string-equal-ignore-case "abc" "ABC"))
+  (string-lessp
+   :eval (string-lessp "abc" "abd")
+   :eval (string-lessp "abc" "abc")
+   :eval (string-lessp "pic4.png" "pic32.png"))
+  (string-greaterp
+   :eval (string-greaterp "abd" "abc")
+   :eval (string-greaterp "abc" "abc"))
+  (string-version-lessp
+   :eval (string-version-lessp "pic4.png" "pic32.png")
+   :eval (string-version-lessp "1.9.3" "1.10.2"))
+  (string-collate-lessp
+   :eval (string-collate-lessp "abc" "abd")))
 
 (define-short-documentation-group vector
   "Making Vectors"
@@ -1131,13 +1208,10 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
    :args (number &rest numbers)
    :eval (= 4 4)
    :eval (= 4.0 4.0)
-   :eval (= 4 5 6 7))
-  (eq
-   :eval (eq 4 4)
-   :eval (eq 4.0 4.0))
+   :eval (= 4 4.0)
+   :eval (= 4 4 4 4))
   (eql
    :eval (eql 4 4)
-   :eval (eql 4 "4")
    :eval (eql 4.0 4.0))
   (/=
    :eval (/= 4 4))
@@ -1148,15 +1222,15 @@ A FUNC form can have any number of `:no-eval' (or 
`:no-value'),
   (<=
    :args (number &rest numbers)
    :eval (<= 4 4)
-   :eval (<= 1 2 3))
+   :eval (<= 1 2 2 3))
   (>
    :args (number &rest numbers)
    :eval (> 4 4)
-   :eval (> 1 2 3))
+   :eval (> 3 2 1))
   (>=
    :args (number &rest numbers)
    :eval (>= 4 4)
-   :eval (>= 1 2 3))
+   :eval (>= 3 2 2 1))
   (zerop
    :eval (zerop 0))
   (cl-plusp
@@ -1440,14 +1514,16 @@ function's documentation in the Info manual"))
                do
                (cl-case type
                  (:eval
+                  (insert "  ")
                   (if (stringp value)
-                      (insert "  " value "\n")
-                    (insert "  ")
-                    (prin1 value (current-buffer))
-                    (insert "\n")
-                    (insert "    " double-arrow " ")
-                    (prin1 (eval value) (current-buffer))
-                    (insert "\n")))
+                      (insert value)
+                    (prin1 value (current-buffer)))
+                  (insert "\n    " double-arrow " ")
+                  (let ((expr (if (stringp value)
+                                  (car (read-from-string value))
+                                value)))
+                    (prin1 (eval expr) (current-buffer)))
+                    (insert "\n"))
                  (:no-eval*
                   (if (stringp value)
                       (insert "  " value "\n")
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 18087bc937..4896f4c293 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -370,7 +370,8 @@ this defaults to the current buffer."
                                                    (min end (point-max)))))
       (if (not (setq disp (get-text-property sub-start 'display object)))
           ;; No old properties in this range.
-          (put-text-property sub-start sub-end 'display (list prop value))
+          (put-text-property sub-start sub-end 'display (list prop value)
+                             object)
         ;; We have old properties.
         (let ((vector nil))
           ;; Make disp into a list.
@@ -390,7 +391,7 @@ this defaults to the current buffer."
           (when vector
             (setq disp (seq-into disp 'vector)))
           ;; Finally update the range.
-          (put-text-property sub-start sub-end 'display disp)))
+          (put-text-property sub-start sub-end 'display disp object)))
       (setq sub-start sub-end))))
 
 ;;;###autoload
@@ -398,7 +399,7 @@ this defaults to the current buffer."
   "Query the user for a process and return the process object."
   ;; Currently supports only the PROCESS argument.
   ;; Must either return a list containing a process, or signal an error.
-  ;; (Returning `nil' would mean the current buffer's process.)
+  ;; (Returning nil would mean the current buffer's process.)
   (unless (fboundp 'process-list)
     (error "Asynchronous subprocesses are not supported on this system"))
   ;; Local function to return cons of a complete-able name, and the
diff --git a/lisp/emacs-lisp/tabulated-list.el 
b/lisp/emacs-lisp/tabulated-list.el
index 206c10a773..595dc9b29d 100644
--- a/lisp/emacs-lisp/tabulated-list.el
+++ b/lisp/emacs-lisp/tabulated-list.el
@@ -263,8 +263,6 @@ Populated by `tabulated-list-init-header'.")
   'header-line-indent--line-number-width "29.1")
 (define-obsolete-function-alias 'tabulated-list-watch-line-number-width
   'header-line-indent--watch-line-number-width "29.1")
-(define-obsolete-function-alias 'tabulated-list-watch-line-number-width
-  'header-line-indent--watch-line-number-width "29.1")
 (define-obsolete-function-alias 'tabulated-list-window-scroll-function
   'header-line-indent--window-scroll-function "29.1")
 
diff --git a/lisp/emulation/viper-cmd.el b/lisp/emulation/viper-cmd.el
index 26793989d0..3b3caaf3e3 100644
--- a/lisp/emulation/viper-cmd.el
+++ b/lisp/emulation/viper-cmd.el
@@ -194,9 +194,9 @@
                           viper-delete-backward-char
                           viper-join-lines
                           viper-delete-char))
-      (memq (viper-event-key last-command-event)
-           '(up down left right (meta f) (meta b)
-                (control n) (control p) (control f) (control b)))))
+      (member (viper-event-key last-command-event)
+             '(up down left right (meta f) (meta b)
+               (control n) (control p) (control f) (control b)))))
 
 (defsubst viper-insert-state-pre-command-sentinel ()
   (or (viper-preserve-cursor-color)
diff --git a/lisp/epa-ks.el b/lisp/epa-ks.el
index 4c539b56a3..bb64b61b8f 100644
--- a/lisp/epa-ks.el
+++ b/lisp/epa-ks.el
@@ -109,7 +109,7 @@ When all keys have been selected, use 
\\[epa-ks-do-key-to-fetch] to
 actually import the keys.
 
 When called interactively, `epa-ks-mark-key-to-fetch' will always
-add a \"F\" tag.  Non-interactivly the tag must be specified by
+add a \"F\" tag.  Non-interactively the tag must be specified by
 setting the TAG parameter."
   (interactive (list "F"))
   (if (region-active-p)
diff --git a/lisp/erc/erc-common.el b/lisp/erc/erc-common.el
index a4046ba9b3..da75d50d61 100644
--- a/lisp/erc/erc-common.el
+++ b/lisp/erc/erc-common.el
@@ -130,7 +130,8 @@ canonical name.")
          (if val "Enable" "Disable")
          " ERC " (symbol-name name) " mode."
          (when localp
-           "\nWith ARG, do so in all buffers for the current connection."))
+           (concat "\nWhen called interactively,"
+                   " do so in all buffers for the current connection.")))
        (interactive ,@(when localp '("p")))
        ,@(if localp
              `((when (derived-mode-p 'erc-mode)
@@ -301,17 +302,11 @@ nil."
 (defun erc-downcase (string)
   "Return a downcased copy of STRING with properties.
 Use the CASEMAPPING ISUPPORT parameter to determine the style."
-  (let* ((mapping (erc--get-isupport-entry 'CASEMAPPING 'single))
-         (inhibit-read-only t))
-    (if (equal mapping "ascii")
-        (downcase string)
-      (with-temp-buffer
-        (insert string)
-        (translate-region (point-min) (point-max)
-                          (if (equal mapping "rfc1459-strict")
-                              erc--casemapping-rfc1459-strict
-                            erc--casemapping-rfc1459))
-        (buffer-string)))))
+  (with-case-table (pcase (erc--get-isupport-entry 'CASEMAPPING 'single)
+                     ("ascii" ascii-case-table)
+                     ("rfc1459-strict" erc--casemapping-rfc1459-strict)
+                     (_ erc--casemapping-rfc1459))
+    (downcase string)))
 
 (define-inline erc-get-channel-user (nick)
   "Find NICK in the current buffer's `erc-channel-users' hash table."
diff --git a/lisp/erc/erc-compat.el b/lisp/erc/erc-compat.el
index abbaafcd93..77625398ab 100644
--- a/lisp/erc/erc-compat.el
+++ b/lisp/erc/erc-compat.el
@@ -176,12 +176,12 @@ If START or END is negative, it counts from the end."
 ;; This hard codes `auth-source-pass-port-separator' to ":"
 (defun erc-compat--29-auth-source-pass--retrieve-parsed (seen e port-number-p)
   (when (string-match (rx (or bot "/")
-                          (or (: (? (group-n 20 (+ (not (in " /:")))) "@")
-                                 (group-n 10 (+ (not (in " /:@"))))
+                          (or (: (? (group-n 20 (+ (not (in "/:")))) "@")
+                                 (group-n 10 (+ (not (in "/:@"))))
                                  (? ":" (group-n 30 (+ (not (in " /:"))))))
-                              (: (group-n 11 (+ (not (in " /:@"))))
+                              (: (group-n 11 (+ (not (in "/:@"))))
                                  (? ":" (group-n 31 (+ (not (in " /:")))))
-                                 (? "/" (group-n 21 (+ (not (in " /:")))))))
+                                 (? "/" (group-n 21 (+ (not (in "/:")))))))
                           eot)
                       e)
     (puthash e `( :host ,(or (match-string 10 e) (match-string 11 e))
@@ -391,8 +391,11 @@ If START or END is negative, it counts from the end."
 
 (cond ((fboundp 'browse-url-irc)) ; 29
       ((boundp 'browse-url-default-handlers) ; 28
-       (cl-pushnew '("\\`irc6?s?://" . erc-compat--29-browse-url-irc)
-                   browse-url-default-handlers))
+       (setf (alist-get "\\`irc6?s?://" browse-url-default-handlers
+                        nil nil (lambda (a _)
+                                  (and (stringp a)
+                                       (string-match-p a "irc://localhost"))))
+             #'erc-compat--29-browse-url-irc))
       ((boundp 'browse-url-browser-function) ; 27
        (require 'browse-url)
        (let ((existing browse-url-browser-function))
diff --git a/lisp/erc/erc-networks.el b/lisp/erc/erc-networks.el
index 19a7ab8643..2e2d093011 100644
--- a/lisp/erc/erc-networks.el
+++ b/lisp/erc/erc-networks.el
@@ -60,6 +60,7 @@
 (declare-function erc-buffer-filter "erc" (predicate &optional proc))
 (declare-function erc-current-nick "erc" nil)
 (declare-function erc-display-error-notice "erc" (parsed string))
+(declare-function erc-display-message "erc" (parsed type buffer msg &rest 
args))
 (declare-function erc-error "erc" (&rest args))
 (declare-function erc-get-buffer "erc" (target &optional proc))
 (declare-function erc-server-buffer "erc" nil)
@@ -1096,7 +1097,8 @@ matching that of the dying buffer."
                                   (erc--target-symbol erc--target))))))))
        ((not (cdr others))))
     (with-current-buffer (car others)
-      (rename-buffer (erc--target-string target)))))
+      (unless (get-buffer (erc--target-string target))
+        (rename-buffer (erc--target-string target))))))
 
 (defun erc-networks-shrink-ids-and-buffer-names ()
   "Recompute network IDs and buffer names, ignoring the current buffer.
@@ -1187,19 +1189,20 @@ rename them with <n> suffixes going from newest to 
oldest."
                  (erc--target-string target)))
          placeholder)
     ;; If we don't exist, claim name temporarily while renaming others
-    (when-let* (namesakes
-                (ex (get-buffer name))
-                ((not (memq ex existing)))
-                (temp-name (generate-new-buffer-name (format "*%s*" name))))
-      (setq existing (remq ex existing))
-      (with-current-buffer ex
-        (rename-buffer temp-name)
-        (setq placeholder (get-buffer-create name))
-        (rename-buffer name 'unique)))
+    (when-let* ((ex (get-buffer name))
+                ((not (memq ex existing))))
+      (if namesakes ; if namesakes is nonempty, it contains ex
+          (with-current-buffer ex
+            (let ((temp-name (generate-new-buffer-name (format "*%s*" name))))
+              (rename-buffer temp-name)
+              (setq placeholder (get-buffer-create name))
+              (rename-buffer name 'unique)))
+        ;; Here, ex must be a server buffer or a non-ERC buffer
+        (setq name (erc-networks--construct-target-buffer-name target))))
     (unless (with-suppressed-warnings ((obsolete erc-reuse-buffers))
               erc-reuse-buffers)
       (when (string-suffix-p ">" name)
-        (setq name (substring name 0 -3))))
+        (setq name (string-trim-right name (rx "<" (+ digit) ">")))))
     (dolist (ex (erc-networks--id-sort-buffers existing))
       (with-current-buffer ex
         (rename-buffer name 'unique)))
@@ -1260,24 +1263,45 @@ given by the `RPL_ISUPPORT' NETWORK parameter."
                return name)
       (and-let* ((vanity (erc--get-isupport-entry 'NETWORK 'single))
                  ((intern vanity))))
+      (erc-networks--id-given erc-networks--id)
       erc-networks--name-missing-sentinel))
 
-(defun erc-networks--set-name (_proc parsed)
+(defvar erc-networks--allow-unknown-network nil
+  "Whether to ignore a failure in identifying the network.
+If you need this as a user option, please say so via \\[erc-bug].
+Otherwise, expect it to vanish at any time.") ; Bug#59976
+
+(defun erc-networks--set-name (proc parsed)
   "Set `erc-network' to the value returned by `erc-networks--determine'.
-Signal an error when the network cannot be determined."
+Print an error message when the network cannot be determined before
+shutting down the connection."
   ;; Always update (possibly clobber) current value, if any.
-  (let ((name (erc-networks--determine)))
-    (when (eq name erc-networks--name-missing-sentinel)
-      ;; This can happen theoretically, e.g., if you're editing some
-      ;; settings interactively on a proxy service that impersonates IRC
-      ;; but aren't being proxied through to a real network.  The
+  (pcase (setq erc-network (erc-networks--determine))
+    ((and (pred (eq (erc-networks--id-given erc-networks--id)))
+          (let m (format "Couldn't determine network. Using given ID `%s'."
+                         erc-network)))
+     (erc-display-message parsed 'notice nil m)
+     nil)
+    ((and
+      (guard (eq erc-network erc-networks--name-missing-sentinel))
+      ;; This can happen theoretically, e.g., when adjusting settings
+      ;; on a proxy service that partially impersonates IRC but isn't
+      ;; currently conveying anything through to a real network.  The
       ;; service may send a 422 but no NETWORK param (or *any* 005s).
-      (let ((m (concat "Failed to determine network. Please set entry for "
-                       erc-server-announced-name " in `erc-networks-alist'.")))
-        (erc-display-error-notice parsed m)
-        (erc-error "Failed to determine network"))) ; beep
-    (setq erc-network name))
-  nil)
+      (let m (concat "Failed to determine network.  Please set entry for \""
+                     erc-server-announced-name "\" in `erc-networks-alist'"
+                     " or consider calling `erc-tls' with the keyword `:id'."
+                     "  See Info:\"(erc) Network Identifier\" for more.")))
+     (require 'info)
+     (erc-display-error-notice parsed m)
+     (if erc-networks--allow-unknown-network
+         (progn
+           (erc-display-error-notice
+            parsed (format "Continuing anyway with network set to `%s'."
+                           erc-network))
+           nil)
+       (delete-process proc)
+       'error))))
 
 ;; This lives here in this file because all the other "on connect"
 ;; MOTD stuff ended up here (but perhaps that needs to change).
@@ -1287,11 +1311,12 @@ Signal an error when the network cannot be determined."
 Copy source (prefix) from MOTD-ish message as a last resort."
   ;; The 004 handler never ran; see 2004-03-10 Diane Murray in change log
   (unless erc-server-announced-name
-    (erc-display-error-notice parsed "Failed to determine server name.")
+    (setq erc-server-announced-name (erc-response.sender parsed))
     (erc-display-error-notice
-     parsed (concat "If this was unexpected, consider reporting it via "
-                    (substitute-command-keys "\\[erc-bug]") "."))
-    (setq erc-server-announced-name (erc-response.sender parsed)))
+     parsed (concat "Failed to determine server name. Using \""
+                    erc-server-announced-name "\" instead."
+                    "  If this was unexpected, consider reporting it via "
+                    (substitute-command-keys "\\[erc-bug]") ".")))
   nil)
 
 (defun erc-unset-network-name (_nick _ip _reason)
diff --git a/lisp/erc/erc-sasl.el b/lisp/erc/erc-sasl.el
index 5b2c93988a..78d02a4638 100644
--- a/lisp/erc/erc-sasl.el
+++ b/lisp/erc/erc-sasl.el
@@ -102,7 +102,7 @@ ERC binds all options defined in this library, such as
 `erc-sasl-password', to their values from entry-point invocation.
 In return, ERC expects a string to send as the SASL password, or
 nil, in which case, ERC will prompt the for input.  See info
-node `(erc) Connecting' for details on ERC's auth-source
+node `(erc) auth-source' for details on ERC's auth-source
 integration."
   :type '(choice (function-item erc-sasl-auth-source-password-as-host)
                  (function-item erc-auth-source-search)
@@ -414,17 +414,30 @@ This doesn't solicit or validate a suite of supported 
mechanisms."
                                        " "))
   (erc-sasl--destroy proc))
 
+(defvar erc-sasl--send-cap-ls nil
+  "Whether to send an opening \"CAP LS\" command.
+This is an escape hatch for picky servers.  If you need it turned
+into a user option, please let ERC know via \\[erc-bug].
+Otherwise, expect it to disappear in subsequent versions.")
+
 (cl-defmethod erc--register-connection (&context (erc-sasl-mode (eql t)))
-  "Send speculative/pipelined CAP and AUTHENTICATE and hope for the best."
+  "Send speculative CAP and pipelined AUTHENTICATE and hope for the best."
   (if-let* ((c (erc-sasl--state-client erc-sasl--state))
             (m (sasl-mechanism-name (sasl-client-mechanism c))))
       (progn
-        (erc-server-send "CAP REQ :sasl")
-        (if (and erc-session-password
-                 (eq :password (alist-get 'password erc-sasl--options)))
-            (let (erc-session-password)
-              (erc-login))
+        (erc-server-send (if erc-sasl--send-cap-ls "CAP LS" "CAP REQ :sasl"))
+        (let ((erc-session-password
+               (and erc-session-password
+                    (not (eq :password (alist-get 'password 
erc-sasl--options)))
+                    erc-session-password))
+              (erc-session-username
+               ;; The username may contain a colon or a space
+               (if (eq :user (alist-get 'user erc-sasl--options))
+                   (erc-current-nick)
+                 erc-session-username)))
           (erc-login))
+        (when erc-sasl--send-cap-ls
+          (erc-server-send "CAP REQ :sasl"))
         (erc-server-send (format "AUTHENTICATE %s" m)))
     (erc-sasl--destroy erc-server-process)))
 
diff --git a/lisp/erc/erc-services.el b/lisp/erc/erc-services.el
index 48953288d1..c2d91ca9d6 100644
--- a/lisp/erc/erc-services.el
+++ b/lisp/erc/erc-services.el
@@ -180,7 +180,7 @@ Called with a subset of keyword parameters known to
 `auth-source-search' and relevant to authenticating to nickname
 services.  In return, ERC expects a string to send as the
 password, or nil, to fall through to the next method, such as
-prompting.  See info node `(erc) Connecting' for details."
+prompting.  See info node `(erc) auth-source' for details."
   :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
   :type '(choice (const erc-auth-source-search)
                  (const nil)
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 268d83dc44..6cfc39c4bd 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -219,7 +219,7 @@ parameters and authentication."
 This variable only exists for legacy reasons.  It's not customizable and
 is limited to a single server password.  Users looking for similar
 functionality should consider auth-source instead.  See info
-node `(auth) Top' and info node `(erc) Connecting'.")
+node `(auth) Top' and info node `(erc) auth-source'.")
 
 (make-obsolete-variable 'erc-password "use auth-source instead" "29.1")
 
@@ -407,15 +407,27 @@ erc-channel-user struct.")
   "Hash table of users on the current server.
 It associates nicknames with `erc-server-user' struct instances.")
 
-(defconst erc--casemapping-rfc1459
-  (make-translation-table
-   '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|) (?~  . ?^))
-   (mapcar (lambda (c) (cons c (+ c 32))) "ABCDEFGHIJKLMNOPQRSTUVWXYZ")))
-
 (defconst erc--casemapping-rfc1459-strict
-  (make-translation-table
-   '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|))
-   (mapcar (lambda (c) (cons c (+ c 32))) "ABCDEFGHIJKLMNOPQRSTUVWXYZ")))
+  (let ((tbl (copy-sequence ascii-case-table))
+        (cup (copy-sequence (char-table-extra-slot ascii-case-table 0))))
+    (set-char-table-extra-slot tbl 0 cup)
+    (set-char-table-extra-slot tbl 1 nil)
+    (set-char-table-extra-slot tbl 2 nil)
+    (pcase-dolist (`(,uc . ,lc) '((?\[ . ?\{) (?\] . ?\}) (?\\ . ?\|)))
+      (aset tbl uc lc)
+      (aset tbl lc lc)
+      (aset cup uc uc))
+    tbl))
+
+(defconst erc--casemapping-rfc1459
+  (let ((tbl (copy-sequence erc--casemapping-rfc1459-strict))
+        (cup (copy-sequence (char-table-extra-slot
+                             erc--casemapping-rfc1459-strict 0))))
+    (set-char-table-extra-slot tbl 0 cup)
+    (aset tbl ?~ ?^)
+    (aset tbl ?^ ?^)
+    (aset cup ?~ ?~)
+    tbl))
 
 (defun erc-add-server-user (nick user)
   "This function is for internal use only.
@@ -1607,11 +1619,12 @@ same manner."
     (if (and (with-suppressed-warnings ((obsolete erc-reuse-buffers))
                erc-reuse-buffers)
              id)
-        (progn
-          (when-let* ((buf (get-buffer (symbol-name id)))
+        (let ((string (symbol-name (erc-networks--id-symbol
+                                    (erc-networks--id-create id)))))
+          (when-let* ((buf (get-buffer string))
                       ((erc-server-process-alive buf)))
-            (user-error  "Session with ID %S already exists" id))
-          (symbol-name id))
+            (user-error  "Session with ID %S already exists" string))
+          string)
       (generate-new-buffer-name (if (and server port)
                                     (if (with-suppressed-warnings
                                             ((obsolete erc-reuse-buffers))
@@ -1970,7 +1983,7 @@ Returns the buffer for the given server or channel."
   (let* ((target (and channel (erc--target-from-string channel)))
          (buffer (erc-get-buffer-create server port nil target id))
          (old-buffer (current-buffer))
-         (old-vars (and (not connect) (buffer-local-variables)))
+         (old-vars (and target (buffer-local-variables)))
          (old-recon-count erc-server-reconnect-count)
          (old-point nil)
          (delayed-modules nil)
@@ -2213,9 +2226,7 @@ then the server and full-name will be set to those values,
 whereas `erc-compute-port' and `erc-compute-nick' will be invoked
 for the values of the other parameters.
 
-When present, ID should be an opaque object used to identify the
-connection unequivocally.  This is rarely needed and not available
-interactively."
+See `erc-tls' for the meaning of ID."
   (interactive (erc-select-read-args))
   (erc-open server port nick full-name t password nil nil nil nil user id))
 
@@ -2242,6 +2253,7 @@ Non-interactively, it takes the keyword arguments
    (server (erc-compute-server))
    (port   (erc-compute-port))
    (nick   (erc-compute-nick))
+   (user   (erc-compute-user))
    password
    (full-name (erc-compute-full-name))
    client-certificate
@@ -2270,11 +2282,11 @@ Example usage:
              \\='(\"/home/bandali/my-cert.key\"
                \"/home/bandali/my-cert.crt\"))
 
-When present, ID should be an opaque object for identifying the
-connection unequivocally.  (In most cases, this would be a string or a
-symbol composed of letters from the Latin alphabet.)  This option is
-generally unneeded, however.  See info node `(erc) Connecting' for use
-cases.  Not available interactively."
+When present, ID should be a symbol or a string to use for naming
+the server buffer and identifying the connection unequivocally.
+See info node `(erc) Network Identifier' for details.  Like USER
+and CLIENT-CERTIFICATE, this parameter cannot be specified
+interactively."
   (interactive (let ((erc-default-port erc-default-port-tls))
                 (erc-select-read-args)))
   (let ((erc-server-connect-function 'erc-open-tls-stream))
@@ -2310,7 +2322,7 @@ message instead, to make debugging easier."
 (defvar erc-debug-irc-protocol-time-format "%FT%T.%6N%z "
   "Timestamp format string for protocol logger.")
 
-(defconst erc-debug-irc-protocol-version "1"
+(defconst erc-debug-irc-protocol-version "2"
   "Protocol log format version number.
 This exists to help tooling track changes to the format.
 
@@ -2321,7 +2333,10 @@ interpreted as email-style headers.  Folding is not 
supported.  A second
 double CRLF, if present, signals the end of a log.  Session resumption
 is not supported.  Logger lines must adhere to the following format:
 TIMESTAMP PEER-NAME FLOW-INDICATOR IRC-MESSAGE CRLF.  Outgoing messages
-are indicated with a >> and incoming with a <<.")
+are indicated with a >> and incoming with a <<.
+
+In version 2, certain outgoing passwords are replaced by a string
+of ten question marks.")
 
 (defvar erc-debug-irc-protocol nil
   "If non-nil, log all IRC protocol traffic to the buffer \"*erc-protocol*\".
@@ -2377,7 +2392,7 @@ workaround."
                       (format "%s:%s" erc-session-server erc-session-port))))
           (ts (when erc-debug-irc-protocol-time-format
                 (format-time-string erc-debug-irc-protocol-time-format))))
-      (when erc--debug-irc-protocol-mask-secrets
+      (when (and outbound erc--debug-irc-protocol-mask-secrets)
         (setq string (erc--mask-secrets string)))
       (with-current-buffer (get-buffer-create "*erc-protocol*")
         (save-excursion
@@ -3208,7 +3223,7 @@ if any.  In return, ERC expects a string to send as the 
server
 password, or nil, to skip the \"PASS\" command completely.  An
 explicit `:password' argument to entry-point commands `erc' and
 `erc-tls' also inhibits lookup, as does setting this option to
-nil.  See info node `(erc) Connecting' for details."
+nil.  See info node `(erc) auth-source' for details."
   :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
   :group 'erc
   :type '(choice (const erc-auth-source-search)
@@ -3223,7 +3238,7 @@ channel.  In return, ERC expects a string to use as the 
channel
 \"key\", or nil to just join the channel normally.  Setting the
 option itself to nil tells ERC to always forgo consulting
 auth-source for channel keys.  For more information, see info
-node `(erc) Connecting'."
+node `(erc) auth-source'."
   :package-version '(ERC . "5.4.1") ; FIXME update when publishing to ELPA
   :group 'erc
   :type '(choice (const erc-auth-source-search)
@@ -5994,18 +6009,17 @@ See also `erc-downcase'."
   (and (erc--target-channel-p erc--target)
        (erc-get-channel-user (erc-current-nick)) t))
 
-;; This function happens to return nil in channel buffers previously
-;; parted or those from which a user had been kicked.  While this
-;; "works" for detecting whether a channel is currently subscribed to,
-;; new code should consider using
+;; While `erc-default-target' happens to return nil in channel buffers
+;; you've parted or from which you've been kicked, using it to detect
+;; whether a channel is currently joined may become unreliable in the
+;; future.  For now, new code should consider using
 ;;
 ;;   (erc-get-channel-user (erc-current-nick))
 ;;
-;; instead.  For retrieving a target regardless of subscription or
-;; connection status, use replacements based on `erc--target'.
-;; (Coming soon.)
-;;
-;; TODO deprecate this
+;; and expect a nicer option eventually.  For retrieving a target
+;; regardless of subscription or connection status, use replacements
+;; based on `erc--target' instead.  See also `erc--default-target'.
+
 (defun erc-default-target ()
   "Return the current default target (as a character string) or nil if none."
   (let ((tgt (car erc-default-recipients)))
@@ -6452,6 +6466,8 @@ non-nil value is found.
 When `erc-auth-source-server-function' is non-nil, call it with NICK for
 the user field and use whatever it returns as the server password."
   (or password (and erc-auth-source-server-function
+                    (not erc--server-reconnecting)
+                    (not erc--target)
                     (funcall erc-auth-source-server-function :user nick))))
 
 (defun erc-compute-full-name (&optional full-name)
diff --git a/lisp/eshell/em-alias.el b/lisp/eshell/em-alias.el
index 9ad218d598..9b75c7a123 100644
--- a/lisp/eshell/em-alias.el
+++ b/lisp/eshell/em-alias.el
@@ -183,7 +183,9 @@ file named by `eshell-aliases-file'.")
   (pcomplete-here (eshell-alias-completions pcomplete-stub)))
 
 (defun eshell-read-aliases-list ()
-  "Read in an aliases list from `eshell-aliases-file'."
+  "Read in an aliases list from `eshell-aliases-file'.
+This is useful after manually editing the contents of the file."
+  (interactive)
   (let ((file eshell-aliases-file))
     (when (file-readable-p file)
       (setq eshell-command-aliases-list
diff --git a/lisp/eshell/em-cmpl.el b/lisp/eshell/em-cmpl.el
index ac82e3f225..2c721eb9e3 100644
--- a/lisp/eshell/em-cmpl.el
+++ b/lisp/eshell/em-cmpl.el
@@ -342,17 +342,23 @@ to writing a completion function."
        (setq pos (1+ pos))))
     (setq posns (cdr posns))
     (cl-assert (= (length args) (length posns)))
-    (let ((a args)
-         (i 0)
-         l)
+    (let ((a args) (i 0) new-start)
       (while a
-       (if (and (consp (car a))
-                (eq (caar a) 'eshell-operator))
-           (setq l i))
-       (setq a (cdr a) i (1+ i)))
-      (and l
-          (setq args (nthcdr (1+ l) args)
-                posns (nthcdr (1+ l) posns))))
+        ;; Remove any top-level `eshell-splice-args' sigils.  These
+        ;; are meant to be rewritten and can't actually be called.
+        (when (and (consp (car a))
+                   (eq (caar a) 'eshell-splice-args))
+          (setcar a (cadar a)))
+        ;; If there's an unreplaced `eshell-operator' sigil, consider
+        ;; the token after it the new start of our arguments.
+        (when (and (consp (car a))
+                   (eq (caar a) 'eshell-operator))
+          (setq new-start i))
+        (setq a (cdr a)
+              i (1+ i)))
+      (when new-start
+       (setq args (nthcdr (1+ new-start) args)
+             posns (nthcdr (1+ new-start) posns))))
     (cl-assert (= (length args) (length posns)))
     (when (and args (eq (char-syntax (char-before end)) ? )
               (not (eq (char-before (1- end)) ?\\)))
diff --git a/lisp/eshell/em-unix.el b/lisp/eshell/em-unix.el
index 4b5e4dd53e..3f7ec618a3 100644
--- a/lisp/eshell/em-unix.el
+++ b/lisp/eshell/em-unix.el
@@ -786,10 +786,14 @@ external command."
 
 (defun eshell-complete-host-reference ()
   "If there is a host reference, complete it."
-  (let ((arg (pcomplete-actual-arg))
-       index)
-    (when (setq index (string-match "@[a-z.]*\\'" arg))
-      (setq pcomplete-stub (substring arg (1+ index))
+  (let ((arg (pcomplete-actual-arg)))
+    (when (string-match
+           (rx ;; Match an "@", but not immediately following a "$".
+               (or string-start (not "$")) "@"
+               (group (* (any "a-z.")))
+               string-end)
+           arg)
+      (setq pcomplete-stub (substring arg (match-beginning 1))
            pcomplete-last-completion-raw t)
       (throw 'pcomplete-completions (pcomplete-read-host-names)))))
 
diff --git a/lisp/eshell/esh-arg.el b/lisp/eshell/esh-arg.el
index f87cc2f20a..8712119671 100644
--- a/lisp/eshell/esh-arg.el
+++ b/lisp/eshell/esh-arg.el
@@ -146,9 +146,10 @@ If POS is nil, the location of point is checked."
 When each function on this hook is called, point will be at the
 current position within the argument list.  The function should either
 return nil, meaning that it did no argument parsing, or it should
-return the result of the parse as a sexp.  It is also responsible for
-moving the point forward to reflect the amount of input text that was
-parsed.
+return the result of the parse as a sexp.  If the function did do
+argument parsing, but the result was nothing at all, it should return
+`eshell-empty-token'.  The function is also responsible for moving the
+point forward to reflect the amount of input text that was parsed.
 
 If the hook determines that it has reached the end of an argument, it
 should call `eshell-finish-arg' to complete processing of the current
@@ -237,13 +238,53 @@ convert the result to a number as well."
         (eshell-convert-to-number result)
       result)))
 
+(defun eshell-concat-groups (quoted &rest args)
+  "Concatenate groups of arguments in ARGS and return the result.
+QUOTED is passed to `eshell-concat' (which see) and, if non-nil,
+allows values to be converted to numbers where appropriate.
+
+ARGS should be a list of lists of arguments, such as that
+produced by `eshell-prepare-slice'.  \"Adjacent\" values of
+consecutive arguments will be passed to `eshell-concat'.  For
+example, if ARGS is
+
+  ((list a) (list b) (list c d e) (list f g)),
+
+then the result will be:
+
+  ((eshell-concat QUOTED a b c)
+   d
+   (eshell-concat QUOTED e f)
+   g)."
+  (let (result current-arg)
+    (dolist (arg args)
+      (when arg
+        (push (car arg) current-arg)
+        (when (length> arg 1)
+          (push (apply #'eshell-concat quoted (nreverse current-arg))
+                result)
+          (dolist (inner (butlast (cdr arg)))
+            (push inner result))
+          (setq current-arg (list (car (last arg)))))))
+    (when current-arg
+      (push (apply #'eshell-concat quoted (nreverse current-arg))
+            result))
+    (nreverse result)))
+
 (defun eshell-resolve-current-argument ()
   "If there are pending modifications to be made, make them now."
   (when eshell-current-argument
     (when eshell-arg-listified
-      (setq eshell-current-argument
-            (append (list 'eshell-concat eshell-current-quoted)
-                    eshell-current-argument))
+      (if-let ((grouped-terms (eshell-prepare-splice
+                               eshell-current-argument)))
+          (setq eshell-current-argument
+                `(eshell-splice-args
+                  (eshell-concat-groups ,eshell-current-quoted
+                                        ,@grouped-terms)))
+        ;; If no terms are spliced, use a simpler command form.
+        (setq eshell-current-argument
+              (append (list 'eshell-concat eshell-current-quoted)
+                      eshell-current-argument)))
       (setq eshell-arg-listified nil))
     (while eshell-current-modifiers
       (setq eshell-current-argument
@@ -260,7 +301,8 @@ argument list in place of the value of the current 
argument."
         (setq eshell-current-argument (car arguments))
       (cl-assert (and (not eshell-arg-listified)
                       (not eshell-current-modifiers)))
-      (setq eshell-current-argument (cons 'eshell-flatten-args arguments))))
+      (setq eshell-current-argument
+            (cons 'eshell-splice-immediately arguments))))
   (throw 'eshell-arg-done t))
 
 (defun eshell-quote-argument (string)
@@ -301,7 +343,8 @@ Point is left at the end of the arguments."
                                 (buffer-substring here (point-max))))
                      (when arg
                        (nconc args
-                              (if (eq (car-safe arg) 'eshell-flatten-args)
+                              (if (eq (car-safe arg)
+                                      'eshell-splice-immediately)
                                   (cdr arg)
                                 (list arg))))))))
               (throw 'eshell-incomplete (if (listp delim)
@@ -325,13 +368,14 @@ Point is left at the end of the arguments."
                   (prog1
                       (char-to-string (char-after))
                     (forward-char)))))
-         (if (not eshell-current-argument)
-             (setq eshell-current-argument result)
-           (unless eshell-arg-listified
-             (setq eshell-current-argument
-                   (list eshell-current-argument)
-                   eshell-arg-listified t))
-           (nconc eshell-current-argument (list result))))))
+          (unless (eq result 'eshell-empty-token)
+            (if (not eshell-current-argument)
+                (setq eshell-current-argument result)
+              (unless eshell-arg-listified
+                (setq eshell-current-argument
+                      (list eshell-current-argument)
+                      eshell-arg-listified t))
+              (nconc eshell-current-argument (list result)))))))
     (when (and outer eshell-current-argument)
       (add-text-properties arg-begin (1+ arg-begin)
                           '(arg-begin t rear-nonsticky
@@ -346,6 +390,10 @@ Point is left at the end of the arguments."
   "A stub function that generates an error if a floating operator is found."
   (error "Unhandled operator in input text"))
 
+(defsubst eshell-splice-args (&rest _args)
+  "A stub function that generates an error if a floating splice is found."
+  (error "Splice operator is not permitted in this context"))
+
 (defsubst eshell-looking-at-backslash-return (pos)
   "Test whether a backslash-return sequence occurs at POS."
   (and (eq (char-after pos) ?\\)
@@ -375,15 +423,24 @@ after are both returned."
     (when (eshell-looking-at-backslash-return (point))
        (throw 'eshell-incomplete ?\\))
     (forward-char 2) ; Move one char past the backslash.
-    ;; If the char is in a quote, backslash only has special meaning
-    ;; if it is escaping a special char.
-    (if eshell-current-quoted
-        (if (memq (char-before) eshell-special-chars-inside-quoting)
-            (list 'eshell-escape-arg (char-to-string (char-before)))
-          (concat "\\" (char-to-string (char-before))))
-      (if (memq (char-before) eshell-special-chars-outside-quoting)
-          (list 'eshell-escape-arg (char-to-string (char-before)))
-        (char-to-string (char-before))))))
+    (let ((special-chars (if eshell-current-quoted
+                             eshell-special-chars-inside-quoting
+                           eshell-special-chars-outside-quoting)))
+      (cond
+       ;; Escaped newlines are extra-special: they expand to an empty
+       ;; token to allow for continuing Eshell commands across
+       ;; multiple lines.
+       ((eq (char-before) ?\n)
+        'eshell-empty-token)
+       ((memq (char-before) special-chars)
+        (list 'eshell-escape-arg (char-to-string (char-before))))
+       ;; If the char is in a quote, backslash only has special
+       ;; meaning if it is escaping a special char.  Otherwise, the
+       ;; result is the literal string "\c".
+       (eshell-current-quoted
+        (concat "\\" (char-to-string (char-before))))
+       (t
+        (char-to-string (char-before)))))))
 
 (defun eshell-parse-literal-quote ()
   "Parse a literally quoted string.  Nothing has special meaning!"
@@ -489,5 +546,32 @@ If the form has no `type', the syntax is parsed as if 
`type' were
                   (char-to-string (char-after)))))
         (goto-char end)))))))
 
+(defun eshell-prepare-splice (args)
+  "Prepare a list of ARGS for splicing, if any arg requested a splice.
+This looks for `eshell-splice-args' as the CAR of each argument,
+and if found, returns a grouped list like:
+
+  ((list arg-1) (list arg-2) spliced-arg-3 ...)
+
+This allows callers of this function to build the final spliced
+list by concatenating each element together, e.g. with (apply
+#'append grouped-list).
+
+If no argument requested a splice, return nil."
+  (let* ((splicep nil)
+         ;; Group each arg like ((list arg-1) (list arg-2) ...),
+         ;; splicing in `eshell-splice-args' args.  This lets us
+         ;; apply spliced args correctly elsewhere.
+         (grouped-args
+          (mapcar (lambda (i)
+                    (if (eq (car-safe i) 'eshell-splice-args)
+                        (progn
+                          (setq splicep t)
+                          (cadr i))
+                      `(list ,i)))
+                  args)))
+    (when splicep
+      grouped-args)))
+
 (provide 'esh-arg)
 ;;; esh-arg.el ends here
diff --git a/lisp/eshell/esh-cmd.el b/lisp/eshell/esh-cmd.el
index 4a41bbe8fa..1fb8499112 100644
--- a/lisp/eshell/esh-cmd.el
+++ b/lisp/eshell/esh-cmd.el
@@ -480,11 +480,16 @@ hooks should be run before and after the command."
   (let ((sym (if eshell-in-pipeline-p
                 'eshell-named-command*
               'eshell-named-command))
-       (cmd (car terms))
-       (args (cdr terms)))
-    (if args
-       (list sym cmd `(list ,@(cdr terms)))
-      (list sym cmd))))
+        (grouped-terms (eshell-prepare-splice terms)))
+    (cond
+     (grouped-terms
+      `(let ((terms (nconc ,@grouped-terms)))
+         (,sym (car terms) (cdr terms))))
+     ;; If no terms are spliced, use a simpler command form.
+     ((cdr terms)
+      (list sym (car terms) `(list ,@(cdr terms))))
+     (t
+      (list sym (car terms))))))
 
 (defvar eshell-command-body)
 (defvar eshell-test-body)
diff --git a/lisp/eshell/esh-opt.el b/lisp/eshell/esh-opt.el
index f52b70fe7a..551317d833 100644
--- a/lisp/eshell/esh-opt.el
+++ b/lisp/eshell/esh-opt.el
@@ -132,7 +132,7 @@ This code doesn't really need to be macro expanded 
everywhere."
                       (setq args (eshell--process-args name args options))
                       nil))))
              (when usage-msg
-               (error "%s" usage-msg))))))
+               (user-error "%s" usage-msg))))))
     (if ext-command
         (throw 'eshell-external
                (eshell-external-command ext-command orig-args))
@@ -237,7 +237,7 @@ remaining characters in SWITCH to be processed later as 
further short
 options.
 
 If no matching handler is found, and an :external command is defined
-(and available), it will be called; otherwise, an error will be
+\(and available), it will be called; otherwise, an error will be
 triggered to say that the switch is unrecognized."
   (let ((switch (eshell--split-switch switch kind))
         (opts options)
diff --git a/lisp/eshell/esh-util.el b/lisp/eshell/esh-util.el
index 0ec11e8a0b..aceca28bef 100644
--- a/lisp/eshell/esh-util.el
+++ b/lisp/eshell/esh-util.el
@@ -362,9 +362,13 @@ Prepend remote identification of `default-directory', if 
any."
   "Convert each element of ARGS into a string value."
   (mapcar #'eshell-stringify args))
 
+(defsubst eshell-list-to-string (list)
+  "Convert LIST into a single string separated by spaces."
+  (mapconcat #'eshell-stringify list " "))
+
 (defsubst eshell-flatten-and-stringify (&rest args)
   "Flatten and stringify all of the ARGS into a single string."
-  (mapconcat #'eshell-stringify (flatten-tree args) " "))
+  (eshell-list-to-string (flatten-tree args)))
 
 (defsubst eshell-directory-files (regexp &optional directory)
   "Return a list of files in the given DIRECTORY matching REGEXP."
diff --git a/lisp/eshell/esh-var.el b/lisp/eshell/esh-var.el
index 57ea42f493..61e9af01a4 100644
--- a/lisp/eshell/esh-var.el
+++ b/lisp/eshell/esh-var.el
@@ -86,6 +86,13 @@
 ;; Returns the length of the value of $EXPR.  This could also be
 ;; done using the `length' Lisp function.
 ;;
+;;   $@EXPR
+;;
+;; Splices the value of $EXPR in-place into the current list of
+;; arguments.  This is analogous to the `,@' token in Elisp
+;; backquotes, and works as if the user typed '$EXPR[0] $EXPR[1]
+;; ... $EXPR[N]'.
+;;
 ;; There are also a few special variables defined by Eshell.  '$$' is
 ;; the value of the last command (t or nil, in the case of an external
 ;; command).  This makes it possible to chain results:
@@ -320,10 +327,9 @@ copied (a.k.a. \"exported\") to the environment of created 
subprocesses."
   "Parse a variable interpolation.
 This function is explicit for adding to `eshell-parse-argument-hook'."
   (when (and (eq (char-after) ?$)
-            (/= (1+ (point)) (point-max)))
+             (/= (1+ (point)) (point-max)))
     (forward-char)
-    (list 'eshell-escape-arg
-         (eshell-parse-variable))))
+    (eshell-parse-variable)))
 
 (defun eshell/define (var-alias definition)
   "Define a VAR-ALIAS using DEFINITION."
@@ -453,6 +459,8 @@ Its purpose is to call `eshell-parse-variable-ref', and 
then to
 process any indices that come after the variable reference."
   (let* ((get-len (when (eq (char-after) ?#)
                    (forward-char) t))
+         (splice (when (eq (char-after) ?@)
+                   (forward-char) t))
         value indices)
     (setq value (eshell-parse-variable-ref get-len)
          indices (and (not (eobp))
@@ -464,7 +472,13 @@ process any indices that come after the variable 
reference."
     (when get-len
       (setq value `(length ,value)))
     (when eshell-current-quoted
-      (setq value `(eshell-stringify ,value)))
+      (if splice
+          (setq value `(eshell-list-to-string ,value)
+                splice nil)
+        (setq value `(eshell-stringify ,value))))
+    (setq value `(eshell-escape-arg ,value))
+    (when splice
+      (setq value `(eshell-splice-args ,value)))
     value))
 
 (defun eshell-parse-variable-ref (&optional modifier-p)
@@ -751,12 +765,13 @@ For example, to retrieve the second element of a user's 
record in
 
 (defun eshell-complete-variable-reference ()
   "If there is a variable reference, complete it."
-  (let ((arg (pcomplete-actual-arg)) index)
-    (when (setq index
-               (string-match
-                (concat "\\$\\(" eshell-variable-name-regexp
-                        "\\)?\\'") arg))
-      (setq pcomplete-stub (substring arg (1+ index)))
+  (let ((arg (pcomplete-actual-arg)))
+    (when (string-match
+           (rx "$" (? (or "#" "@"))
+               (? (group (regexp eshell-variable-name-regexp)))
+               string-end)
+           arg)
+      (setq pcomplete-stub (substring arg (match-beginning 1)))
       (throw 'pcomplete-completions (eshell-variables-list)))))
 
 (defun eshell-variables-list ()
diff --git a/lisp/external-completion.el b/lisp/external-completion.el
new file mode 100644
index 0000000000..e1c3d76314
--- /dev/null
+++ b/lisp/external-completion.el
@@ -0,0 +1,176 @@
+;;; external-completion.el --- Let external tools control completion style  
-*- lexical-binding: t; -*-
+
+;; Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+;; Version: 0.1
+;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
+;; Maintainer: João Távora <joaotavora@gmail.com>
+;; Keywords:
+
+;; 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:
+
+;; Written by Stefan Monnier circa 2016.  Variants of this code have
+;; been working stably in SLY and other packages for a long time.
+
+;; The `external' completion style is used with a "programmable
+;; completion" table that gathers completions from an external tool
+;; such as a shell utility, an inferior process, an http server.
+
+;; The table and external tool are fully in control of the matching of
+;; the pattern string to the potential candidates of completion.  When
+;; `external' is in use, the usual styles configured by the user or
+;; other in `completion-styles' are ignored.
+;;
+;; This compromise is for speed: all other styles need the full data
+;; set to be available in Emacs' addressing space, which is often slow
+;; if not completely unfeasible.
+;;
+;; To make use of the `external' style the function
+;; `external-completion-table' should be used.  See its docstring.
+
+;;; Code:
+(require 'cl-lib)
+
+(add-to-list 'completion-styles-alist
+             '(external
+               external-completion--try-completion
+               external-completion--all-completions
+               "Ad-hoc completion style provided by the completion table."))
+
+(defun external-completion-table (category lookup
+                                           &optional metadata
+                                           try-completion-function)
+  "Make completion table using the `external' completion style.
+
+The `external' style is particularly useful when the caller
+interfaces with an external tool that provides completions.  This
+may be a shell utility, an inferior process, an http server, etc.
+Given a pattern string, the external tool matches it to an
+arbitrarily large set of candidates.  Since the full set doesn't
+need to be transferred to Emacs's address space, this often
+results in much faster overall experience, at the expense of the
+convenience of offered by other completion styles.
+
+CATEGORY is a symbol uniquely naming the external tool.  This
+function links CATEGORY to the style `external', by modifying
+`completion-category-defaults', overriding any styles normally
+set in `completion-styles'.
+
+LOOKUP is a function taking a string PATTERN and a number
+POINT. The function should contact the tool and return a list of
+strings representing the completions for PATTERN given that POINT
+is the location of point within it.  LOOKUP decides if PATTERN is
+interpreted as a substring, a regular expression, or any other
+type of matching method.  The strings returned may be propertized
+with `completions-common-part' to illustrate the specific method
+used.  LOOKUP may ignore POINT if it doesn't meaningfully alter
+the results.
+
+LOOKUP is a synchronous blocking function.  Since it contacts an
+external tool, it's possible that it takes significant time to
+return results.  To maintain Emacs's responsiveness, LOOKUP
+should detect pending user input using `while-no-input' or
+`sit-for' (which see).  In those cases, LOOKUP should attempt to
+cancel the request (if possible) and immediately return any
+non-list.
+
+METADATA is an alist of additional properties such as
+`cycle-sort-function' to associate with CATEGORY.  This means
+that the caller may still retain control the sorting of the
+candidates while the tool controls the matching.
+
+Optional TRY-COMPLETION-FUNCTION helps some frontends partially
+or fully expand PATTERN before finishing the completion
+operation.  If supplied, it is a function taking a (PATTERN POINT
+ALL-COMPLETIONS), where PATTERN and POINT are as described above
+and ALL-COMPLETIONS are gathered by LOOKUP for these
+arguments (this function ensures LOOKUP isn't called more than
+needed).  If you know the matching method that the external tool
+using, TRY-COMPLETION-FUNCTION may return a cons
+cell (EXPANDED-PATTERN . NEW-POINT).  For example, if the tool is
+completing by prefix, one could call `try-completion' to find the
+largest common prefix in ALL-COMPLETIONS and then return that as
+EXPANDED-PATTERN."
+  (let ((probe (alist-get category completion-category-defaults)))
+    (if probe
+        (cl-assert (equal '(external) (alist-get 'styles probe))
+                   nil "Category `%s' must only use `external' style" category)
+        (push `(,category (styles external))
+              completion-category-defaults)))
+  (let ((cache (make-hash-table :test #'equal)))
+    (cl-flet ((lookup-internal (string point)
+                (let* ((key (cons string point))
+                       (probe (gethash key cache 'external--notfound)))
+                  (if (eq probe 'external--notfound)
+                      (puthash key (funcall lookup string point) cache)
+                    probe))))
+      (lambda (string pred action)
+        (pcase action
+          (`metadata
+           `(metadata (category . ,category) . ,metadata))
+          ;; Note: the `--tryc' `--allc' suffixes are made akward on
+          ;; purpose, so it's easy to pick them apart from the jungle
+          ;; of combinations of "try" and "all" and "completion" that
+          ;; inhabit Emacs's completion logic.
+          (`(external-completion--tryc . ,point)
+           ;; FIXME: Obey `pred'?  Pass it to `try-completion-function'?
+           `(external-completion--tryc
+             . ,(if try-completion-function
+                    (funcall try-completion-function
+                             string
+                             point
+                             (lookup-internal string point))
+                  (cons string point))))
+          (`(external-completion--allc . ,point)
+           (let ((all (lookup-internal string point)))
+             `(external-completion--allc
+               . ,(if pred (cl-remove-if-not pred all) all))))
+          (`(boundaries . ,_) nil)
+          (_method
+           (let ((all (lookup-internal string (length string))))
+             ;; This branch might be taken:
+             ;;
+             ;; * when users work around
+             ;;   `completion-category-defaults' (via
+             ;;   `completion-category-overrides') and access this
+             ;;   table with another completion style.  We assume
+             ;;   these users know what they are doing, but it might
+             ;;   not work very well, as this whatever is in `all'
+             ;;   very often doesn't equate the full set of candidates
+             ;;   (many tools cap to sth like 100-1000 results).
+             ;;
+             ;; * when `_method' is nil or `lambda' which some
+             ;;   frontends will invoke.  Here, `all' should be
+             ;;   sufficient information for `complete-with-action' to
+             ;;   do the job correctly.
+             (complete-with-action action all string pred))))))))
+
+(defun external-completion--call (op string table pred point)
+  (when (functionp table)
+    (let ((res (funcall table string pred (cons op point))))
+      (when (eq op (car-safe res))
+        (cdr res)))))
+
+(defun external-completion--try-completion (string table pred point)
+  (external-completion--call 'external-completion--tryc string table pred 
point))
+
+(defun external-completion--all-completions (string table pred point)
+  (external-completion--call 'external-completion--allc string table pred 
point))
+
+(provide 'external-completion)
+;;; external-completion.el ends here
diff --git a/lisp/files.el b/lisp/files.el
index d785d4fd75..f352d3a9a7 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -6193,18 +6193,17 @@ instance of such commands."
       (rename-buffer (generate-new-buffer-name base-name))
       (force-mode-line-update))))
 
-(defun files--ensure-directory (dir)
-  "Make directory DIR if it is not already a directory.  Return nil."
+(defun files--ensure-directory (mkdir dir)
+  "Use function MKDIR to make directory DIR if it is not already a directory.
+Return non-nil if DIR is already a directory."
   (condition-case err
-      (make-directory-internal dir)
+      (funcall mkdir dir)
     (error
-     (unless (file-directory-p dir)
-       (signal (car err) (cdr err))))))
+     (or (file-directory-p dir)
+        (signal (car err) (cdr err))))))
 
 (defun make-directory (dir &optional parents)
   "Create the directory DIR and optionally any nonexistent parent dirs.
-If DIR already exists as a directory, signal an error, unless
-PARENTS is non-nil.
 
 Interactively, the default choice of directory to create is the
 current buffer's default directory.  That is useful when you have
@@ -6214,8 +6213,9 @@ Noninteractively, the second (optional) argument PARENTS, 
if
 non-nil, says whether to create parent directories that don't
 exist.  Interactively, this happens by default.
 
-If creating the directory or directories fail, an error will be
-raised."
+Return non-nil if PARENTS is non-nil and DIR already exists as a
+directory, and nil if DIR did not already exist but was created.
+Signal an error if unsuccessful."
   (interactive
    (list (read-file-name "Make directory: " default-directory default-directory
                         nil nil)
@@ -6223,25 +6223,32 @@ raised."
   ;; If default-directory is a remote directory,
   ;; make sure we find its make-directory handler.
   (setq dir (expand-file-name dir))
-  (let ((handler (find-file-name-handler dir 'make-directory)))
-    (if handler
-       (funcall handler 'make-directory dir parents)
-      (if (not parents)
-         (make-directory-internal dir)
-       (let ((dir (directory-file-name (expand-file-name dir)))
-             create-list parent)
-         (while (progn
-                  (setq parent (directory-file-name
-                                (file-name-directory dir)))
-                  (condition-case ()
-                      (files--ensure-directory dir)
-                    (file-missing
-                     ;; Do not loop if root does not exist (Bug#2309).
-                     (not (string= dir parent)))))
-           (setq create-list (cons dir create-list)
-                 dir parent))
-         (dolist (dir create-list)
-            (files--ensure-directory dir)))))))
+  (let ((mkdir (if-let ((handler (find-file-name-handler dir 'make-directory)))
+                  #'(lambda (dir)
+                      ;; Use 'ignore' since the handler might be designed for
+                      ;; Emacs 28-, so it might return an (undocumented)
+                      ;; non-nil value, whereas the Emacs 29+ convention is
+                      ;; to return nil here.
+                      (ignore (funcall handler 'make-directory dir)))
+                 #'make-directory-internal)))
+    (if (not parents)
+        (funcall mkdir dir)
+      (let ((dir (directory-file-name (expand-file-name dir)))
+            already-dir create-list parent)
+        (while (progn
+                 (setq parent (directory-file-name
+                               (file-name-directory dir)))
+                 (condition-case ()
+                     (ignore (setq already-dir
+                                   (files--ensure-directory mkdir dir)))
+                   (error
+                    ;; Do not loop if root does not exist (Bug#2309).
+                    (not (string= dir parent)))))
+          (setq create-list (cons dir create-list)
+                dir parent))
+        (dolist (dir create-list)
+          (setq already-dir (files--ensure-directory mkdir dir)))
+        already-dir))))
 
 (defun make-empty-file (filename &optional parents)
   "Create an empty file FILENAME.
@@ -6435,7 +6442,7 @@ into NEWNAME instead."
   ;; copy-directory handler.
   (let ((handler (or (find-file-name-handler directory 'copy-directory)
                     (find-file-name-handler newname 'copy-directory)))
-       (follow parents))
+       follow)
     (if handler
        (funcall handler 'copy-directory directory
                  newname keep-time parents copy-contents)
@@ -6455,19 +6462,24 @@ into NEWNAME instead."
                                    t)
              (make-symbolic-link target newname t)))
         ;; Else proceed to copy as a regular directory
-        (cond ((not (directory-name-p newname))
+       ;; first by creating the destination directory if needed,
+       ;; preparing to follow any symlink to a directory we did not create.
+       (setq follow
+           (if (not (directory-name-p newname))
               ;; If NEWNAME is not a directory name, create it;
               ;; that is where we will copy the files of DIRECTORY.
-              (make-directory newname parents))
+              (make-directory newname parents)
              ;; NEWNAME is a directory name.  If COPY-CONTENTS is non-nil,
              ;; create NEWNAME if it is not already a directory;
              ;; otherwise, create NEWNAME/[DIRECTORY-BASENAME].
-             ((if copy-contents
-                  (or parents (not (file-directory-p newname)))
+             (unless copy-contents
                 (setq newname (concat newname
                                       (file-name-nondirectory directory))))
-              (make-directory (directory-file-name newname) parents))
-             (t (setq follow t)))
+             (condition-case err
+                 (make-directory (directory-file-name newname) parents)
+               (error
+                (or (file-directory-p newname)
+                    (signal (car err) (cdr err)))))))
 
         ;; Copy recursively.
         (dolist (file
@@ -8497,7 +8509,7 @@ Otherwise, trash FILENAME using the freedesktop.org 
conventions,
           (unless (file-directory-p trash-dir)
             (make-directory trash-dir t))
           ;; Ensure that the trashed file-name is unique.
-          (if (file-exists-p new-fn)
+          (if (file-attributes new-fn)
               (let ((version-control t)
                     (backup-directory-alist nil))
                 (setq new-fn (car (find-backup-file-name new-fn)))))
@@ -8574,7 +8586,7 @@ Otherwise, trash FILENAME using the freedesktop.org 
conventions,
                  ;; We're checking further down whether the info file
                  ;; exists, but the file name may exist in the trash
                  ;; directory even if there is no info file for it.
-                 (when (file-exists-p
+                 (when (file-attributes
                         (file-name-concat trash-files-dir files-base))
                    (setq overwrite t
                          files-base (file-name-nondirectory
@@ -8612,7 +8624,7 @@ Otherwise, trash FILENAME using the freedesktop.org 
conventions,
                 (let ((delete-by-moving-to-trash nil)
                       (new-fn (file-name-concat trash-files-dir files-base)))
                    (if (or (not is-directory)
-                           (not (file-exists-p new-fn)))
+                           (not (file-attributes new-fn)))
                        (rename-file fn new-fn overwrite)
                      (copy-directory fn
                                      (file-name-as-directory new-fn)
diff --git a/lisp/gnus/ChangeLog.2 b/lisp/gnus/ChangeLog.2
index fd5fa0542f..4ac69b575f 100644
--- a/lisp/gnus/ChangeLog.2
+++ b/lisp/gnus/ChangeLog.2
@@ -10070,7 +10070,7 @@
        * gnus-group.el (gnus-group-delete-group): Nix the entry in
        gnus-cache-active-hashtb.
 
-       * gnus-agent.el (gnus-agent-mark-unread-afer-downloaded): New variable.
+       * gnus-agent.el (gnus-agent-mark-unread-after-downloaded): New variable.
        (gnus-agent-summary-fetch-group): Use it.
 
        * gnus-msg.el (gnus-debug-files): New variable.
diff --git a/lisp/gnus/ChangeLog.3 b/lisp/gnus/ChangeLog.3
index 3b41e9edc9..8c1073dc8d 100644
--- a/lisp/gnus/ChangeLog.3
+++ b/lisp/gnus/ChangeLog.3
@@ -6032,7 +6032,7 @@
        Make `default' the default, for compatibility with open-network-stream.
        Handle the no-parameter case exactly as open-network-stream, with no
        additional stream processing.  Search plists using plist-get.
-       Explicitly add :end-of-commend parameter if it is missing.
+       Explicitly add :end-of-comment parameter if it is missing.
        (proto-stream-open-default): Rename from
        proto-stream-open-network-only.  Return 'default as the type.
        (proto-stream-open-starttls): Rename from proto-stream-open-network.
diff --git a/lisp/gnus/gnus-icalendar.el b/lisp/gnus/gnus-icalendar.el
index 1bffdf3513..f3665c3f1a 100644
--- a/lisp/gnus/gnus-icalendar.el
+++ b/lisp/gnus/gnus-icalendar.el
@@ -603,7 +603,7 @@ is searched."
     (when file
       (switch-to-buffer (find-file file))
       (goto-char (org-find-entry-with-id (gnus-icalendar-event:uid event)))
-      (org-show-entry))))
+      (org-fold-show-entry))))
 
 
 (defun gnus-icalendar--update-org-event (event reply-status &optional org-file)
diff --git a/lisp/gnus/nnmaildir.el b/lisp/gnus/nnmaildir.el
index faa288934d..3fb87f3a71 100644
--- a/lisp/gnus/nnmaildir.el
+++ b/lisp/gnus/nnmaildir.el
@@ -296,7 +296,7 @@ This variable is set by `nnmaildir-request-article'.")
      (if (file-attributes file) (delete-file file))))
 (defun nnmaildir--mkdir (dir)
   (or (file-exists-p (file-name-as-directory dir))
-      (make-directory-internal (directory-file-name dir))))
+      (make-directory (directory-file-name dir))))
 (defun nnmaildir--mkfile (file)
   (write-region "" nil file nil 'no-message))
 (defun nnmaildir--delete-dir-files (dir ls)
diff --git a/lisp/icomplete.el b/lisp/icomplete.el
index ef710d582d..983931c20c 100644
--- a/lisp/icomplete.el
+++ b/lisp/icomplete.el
@@ -416,7 +416,6 @@ if that doesn't produce a completion match."
                 icomplete-scroll (not (null icomplete-vertical-mode))
                 completion-styles '(flex)
                 completion-flex-nospace nil
-                completion-category-defaults nil
                 completion-ignore-case t
                 read-buffer-completion-ignore-case t
                 read-file-name-completion-ignore-case t)))
diff --git a/lisp/ido.el b/lisp/ido.el
index 77e4dd447d..92b4370cb4 100644
--- a/lisp/ido.el
+++ b/lisp/ido.el
@@ -2435,7 +2435,7 @@ If cursor is not at the end of the user input, move to 
end of input."
                                 filename))
              (ido-record-command method dirname)
              (ido-record-work-directory dirname)
-             (make-directory-internal dirname)
+             (make-directory dirname)
              (funcall method dirname))
             (t
              ;; put make-directory command on history
diff --git a/lisp/international/ogonek.el b/lisp/international/ogonek.el
index ac9a213ec7..216d2fd0f2 100644
--- a/lisp/international/ogonek.el
+++ b/lisp/international/ogonek.el
@@ -214,7 +214,7 @@ The functions come in the following groups.
  is stored in the constant `ogonek-name-encoding-alist'.
 
  The `ogonek' functions refer to five variables in which the suggested
- answers to dialogue questions are stored.  The variables and their
+ answers to dialog questions are stored.  The variables and their
  default values are:
 
    ogonek-from-encoding           iso8859-2
@@ -266,7 +266,7 @@ The functions come in the following groups.
   (switch-to-buffer " *ogonek-how*")
   (goto-char (point-min)))
 
-;; ---- Variables keeping the suggested answers to dialogue questions -----
+;; ---- Variables keeping the suggested answers to dialog questions -----
 (defvar ogonek-encoding-choices
   (cons 'choice
        (mapcar (lambda (x) (list 'const (car x)))
diff --git a/lisp/isearch.el b/lisp/isearch.el
index bc3697deb0..6a17d18c45 100644
--- a/lisp/isearch.el
+++ b/lisp/isearch.el
@@ -4435,7 +4435,7 @@ CASE-FOLD: The value of `isearch-case-fold' to use for 
lazy
 highlighting.
 LAX-WHITESPACE: The value of `isearch-lax-whitespace' and
 `isearch-regexp-lax-whitespace' to use for lazy highlighting."
-  (if (not highlight)
+  (if (or (not highlight) (minibufferp))
       #'ignore
     (let ((unwind (make-symbol "minibuffer-lazy-highlight--unwind"))
           (after-change (make-symbol 
"minibuffer-lazy-highlight--after-change"))
diff --git a/lisp/jsonrpc.el b/lisp/jsonrpc.el
index 90833e1c1d..2d562610b3 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.15
+;; Version: 1.0.16
 ;; Package-Requires: ((emacs "25.2"))
 
 ;; This is a GNU ELPA :core package.  Avoid functionality that is not
@@ -548,11 +548,26 @@ With optional CLEANUP, kill any associated buffers."
         (delete-process proc)
         (funcall (jsonrpc--on-shutdown connection) connection)))))
 
-(defun jsonrpc--process-filter (proc string)
+(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* ((inhibit-read-only t)
+             (jsonrpc--in-process-filter t)
              (connection (process-get proc 'jsonrpc-connection))
              (expected-bytes (jsonrpc--expected-bytes connection)))
         ;; Insert the text, advancing the process marker.
diff --git a/lisp/keymap.el b/lisp/keymap.el
index eaeba96644..b355f68aa2 100644
--- a/lisp/keymap.el
+++ b/lisp/keymap.el
@@ -147,7 +147,7 @@ in KEYMAP as NEWDEF those keys that are defined as OLDDEF 
in OLDMAP.
 If you don't specify OLDMAP, you can usually get the same results
 in a cleaner way with command remapping, like this:
   (define-key KEYMAP [remap OLDDEF] NEWDEF)
-\n(fn OLDDEF NEWDEF KEYMAP &optional OLDMAP)"
+\n(fn KEYMAP OLDDEF NEWDEF &optional OLDMAP)"
   ;; Don't document PREFIX in the doc string because we don't want to
   ;; advertise it.  It's meant for recursive calls only.  Here's its
   ;; meaning
diff --git a/lisp/language/european.el b/lisp/language/european.el
index 937215074b..18b72bd3b2 100644
--- a/lisp/language/european.el
+++ b/lisp/language/european.el
@@ -585,7 +585,7 @@ and it selects the Spanish tutorial."))
             (nonascii-translation . iso-8859-9)
             (unibyte-display . iso-latin-5)
             (input-method . "turkish-postfix")
-            (sample-text . "Turkish (Türkçe)   Merhaba")
+            (sample-text . "Turkish (Türkçe)   Esenlikler / Merhaba")
             (setup-function . turkish-case-conversion-enable)
             (exit-function . turkish-case-conversion-disable)
             (documentation . "Support for Turkish.
diff --git a/lisp/language/indian.el b/lisp/language/indian.el
index 4994cfdc7a..f70f7fcce1 100644
--- a/lisp/language/indian.el
+++ b/lisp/language/indian.el
@@ -552,24 +552,40 @@ environment."))
    char-script-table))
 
 ;; Brahmi composition rules
-(let ((consonant     "[\U00011013-\U00011034]")
-      (non-consonant "[^\U00011013-\U00011034\U00011046\U0001107F]")
-      (vowel         "[\U00011038-\U00011045]")
-      (numeral       "[\U00011052-\U00011065]")
-      (multiplier    "[\U00011064\U00011065]")
-      (virama        "\U00011046")
-      (number-joiner "\U0001107F"))
+(let ((consonant            "[\x11013-\x11037\x11075]")
+      (independent-vowel    "[\x11005-\x11012\x11071\x11072]")
+      (vowel                "[\x11038-\x11045\x11073\x11074]")
+      (nasal                "[\x11000\x11001]")
+      (virama               "\x11046")
+      (jivhamuliya          "\x11003")
+      (upadhmaniya          "\x11004")
+      (ka-kha               "[\x11013\x11014]")
+      (pa-pha               "[\x11027\x11028]")
+      (number-joiner        "\x1107F")
+      (numeral              "[\x11052-\x11065]")
+      (multiplier           "[\x11064\x11065]"))
   (set-char-table-range composition-function-table
-                       '(#x11046 . #x11046)
+                        '(#x11046 . #x11046)
                         (list (vector
-                               ;; Consonant conjuncts
-                               (concat consonant "\\(?:" virama consonant 
"\\)+"
-                                       vowel "?")
+                               ;; Consonant based syllables
+                               (concat consonant "\\(?:" virama consonant
+                                       "\\)*\\(?:" virama "\\|" vowel "*"
+                                       nasal "?\\)")
                                1 'font-shape-gstring)
                               (vector
-                               ;; Vowelless consonants
-                               (concat consonant virama non-consonant)
+                               ;; Vowel based syllables
+                               (concat independent-vowel virama "?" vowel "?" 
nasal "?")
                                1 'font-shape-gstring)))
+  (set-char-table-range composition-function-table
+                        '(#x11003 . #x11004)
+                        (list (vector
+                               ;; Velar fricative
+                               (concat jivhamuliya ka-kha "?")
+                               0 'font-shape-gstring)
+                              (vector
+                               ;; Bilabial fricative
+                               (concat upadhmaniya pa-pha "?")
+                               0 'font-shape-gstring)))
   (set-char-table-range composition-function-table
                         '(#x1107F . #x1107F)
                         (list (vector
diff --git a/lisp/ldefs-boot.el b/lisp/ldefs-boot.el
index 1c049107f0..2639c5cceb 100644
--- a/lisp/ldefs-boot.el
+++ b/lisp/ldefs-boot.el
@@ -1944,6 +1944,85 @@ Major mode for editing BibTeX style files.
 (register-definition-prefixes "bibtex-style" '("bibtex-style-"))
 
 
+;;; Generated autoloads from use-package/bind-key.el
+
+(push (purecopy '(bind-key 2 4 1)) package--builtin-versions)
+(autoload 'bind-key "bind-key" "\
+Bind KEY-NAME to COMMAND in KEYMAP (`global-map' if not passed).
+
+KEY-NAME may be a vector, in which case it is passed straight to
+`define-key'.  Or it may be a string to be interpreted as
+spelled-out keystrokes, e.g., \"C-c C-z\".  See the documentation
+of `edmacro-mode' for details.
+
+COMMAND must be an interactive function or lambda form.
+
+KEYMAP, if present, should be a keymap variable or symbol.
+For example:
+
+  (bind-key \"M-h\" #\\='some-interactive-function my-mode-map)
+
+  (bind-key \"M-h\" #\\='some-interactive-function \\='my-mode-map)
+
+If PREDICATE is non-nil, it is a form evaluated to determine when
+a key should be bound. It must return non-nil in such cases.
+Emacs can evaluate this form at any time that it does redisplay
+or operates on menu data structures, so you should write it so it
+can safely be called at any time.
+
+(fn KEY-NAME COMMAND &optional KEYMAP PREDICATE)" nil t)
+(autoload 'unbind-key "bind-key" "\
+Unbind the given KEY-NAME, within the KEYMAP (if specified).
+See `bind-key' for more details.
+
+(fn KEY-NAME &optional KEYMAP)" nil t)
+(autoload 'bind-key* "bind-key" "\
+Similar to `bind-key', but overrides any mode-specific bindings.
+
+(fn KEY-NAME COMMAND &optional PREDICATE)" nil t)
+(autoload 'bind-keys "bind-key" "\
+Bind multiple keys at once.
+
+Accepts keyword arguments:
+:map MAP               - a keymap into which the keybindings should be
+                         added
+:prefix KEY            - prefix key for these bindings
+:prefix-map MAP        - name of the prefix map that should be created
+                         for these bindings
+:prefix-docstring STR  - docstring for the prefix-map variable
+:menu-name NAME        - optional menu string for prefix map
+:repeat-docstring STR  - docstring for the repeat-map variable
+:repeat-map MAP        - name of the repeat map that should be created
+                         for these bindings. If specified, the
+                         `repeat-map' property of each command bound
+                         (within the scope of the `:repeat-map' keyword)
+                         is set to this map.
+:exit BINDINGS         - Within the scope of `:repeat-map' will bind the
+                         key in the repeat map, but will not set the
+                         `repeat-map' property of the bound command.
+:continue BINDINGS     - Within the scope of `:repeat-map' forces the
+                         same behavior as if no special keyword had
+                         been used (that is, the command is bound, and
+                         it's `repeat-map' property set)
+:filter FORM           - optional form to determine when bindings apply
+
+The rest of the arguments are conses of keybinding string and a
+function symbol (unquoted).
+
+(fn &rest ARGS)" nil t)
+(autoload 'bind-keys* "bind-key" "\
+Bind multiple keys at once, in `override-global-map'.
+Accepts the same keyword arguments as `bind-keys' (which see).
+
+This binds keys in such a way that bindings are not overridden by
+other modes.  See `override-global-mode'.
+
+(fn &rest ARGS)" nil t)
+(autoload 'describe-personal-keybindings "bind-key" "\
+Display all the personal keybindings defined by `bind-key'." t)
+(register-definition-prefixes "bind-key" '("bind-key" "override-global-m" 
"personal-keybindings"))
+
+
 ;;; Generated autoloads from emacs-lisp/bindat.el
 
 (register-definition-prefixes "bindat" '("bindat-"))
@@ -2841,9 +2920,11 @@ and corresponding effects.
 
 ;;; Generated autoloads from progmodes/c-ts-mode.el
 
-(autoload 'c-ts-mode--base-mode "c-ts-mode" "\
+(autoload 'c-ts-base-mode "c-ts-mode" "\
 Major mode for editing C, powered by tree-sitter.
 
+\\{c-ts-mode-map}
+
 (fn)" t)
 (autoload 'c-ts-mode "c-ts-mode" "\
 Major mode for editing C, powered by tree-sitter.
@@ -2853,7 +2934,7 @@ Major mode for editing C, powered by tree-sitter.
 Major mode for editing C++, powered by tree-sitter.
 
 (fn)" t)
-(register-definition-prefixes "c-ts-mode" '("c-ts-"))
+(register-definition-prefixes "c-ts-mode" '("c-ts-mode-"))
 
 
 ;;; Generated autoloads from calendar/cal-bahai.el
@@ -4548,6 +4629,16 @@ For use inside Lisp programs, see also 
`c-macro-expansion'.
 (register-definition-prefixes "cmacexp" '("c-macro-"))
 
 
+;;; Generated autoloads from progmodes/cmake-ts-mode.el
+
+(add-to-list 'auto-mode-alist '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)$" . 
cmake-ts-mode))
+(autoload 'cmake-ts-mode "cmake-ts-mode" "\
+Major mode for editing CMake files, powered by tree-sitter.
+
+(fn)" t)
+(register-definition-prefixes "cmake-ts-mode" '("cmake-ts-mode-"))
+
+
 ;;; Generated autoloads from cmuscheme.el
 
 (autoload 'run-scheme "cmuscheme" "\
@@ -7897,6 +7988,16 @@ it is disabled.
 (register-definition-prefixes "doc-view" '("doc-view-"))
 
 
+;;; Generated autoloads from progmodes/dockerfile-ts-mode.el
+
+(add-to-list 'auto-mode-alist 
'("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" . 
dockerfile-ts-mode))
+(autoload 'dockerfile-ts-mode "dockerfile-ts-mode" "\
+Major mode for editing Dockerfiles, powered by tree-sitter.
+
+(fn)" t)
+(register-definition-prefixes "dockerfile-ts-mode" '("dockerfile-ts-mode--"))
+
+
 ;;; Generated autoloads from play/doctor.el
 
 (autoload 'doctor "doctor" "\
@@ -11277,6 +11378,12 @@ This is used only in conjunction with 
`expand-add-abbrevs'." t)
 (register-definition-prefixes "srecode/expandproto" '("srecode-"))
 
 
+;;; Generated autoloads from external-completion.el
+
+(push (purecopy '(external-completion 0 1)) package--builtin-versions)
+(register-definition-prefixes "external-completion" '("external-completion-"))
+
+
 ;;; Generated autoloads from cedet/srecode/extract.el
 
 (register-definition-prefixes "srecode/extract" '("srecode-extract"))
@@ -23377,11 +23484,11 @@ regular package, but it will not remove a VC package.
 (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
-for use with Emacs; use `package-vc-link-directory' for setting
-the package up after this function finishes.
-Optional argument REV means to clone a specific version of the
-package; it defaults to the last version available from the
-package's repository.  If REV has the special value
+for use with Emacs; use `package-vc-install-from-checkout' for
+setting the package up after this function finishes.  Optional
+argument REV means to clone a specific version of the package; it
+defaults to the last version available from the package's
+repository.  If REV has the special value
 `:last-release' (interactively, the prefix argument), that stands
 for the last released version of the package.
 
@@ -24970,7 +25077,7 @@ Open profile FILENAME.
 
 ;;; Generated autoloads from progmodes/project.el
 
-(push (purecopy '(project 0 8 3)) package--builtin-versions)
+(push (purecopy '(project 0 9 3)) package--builtin-versions)
 (autoload 'project-current "project" "\
 Return the project instance in DIRECTORY, defaulting to `default-directory'.
 
@@ -24982,8 +25089,8 @@ project instance.
 
 The \"transient\" project instance is a special kind of value
 which denotes a project rooted in that directory and includes all
-the files under the directory except for those that should be
-ignored (per `project-ignores').
+the files under the directory except for those that match entries
+in `vc-directory-exclusion-list' or `grep-find-ignored-files'.
 
 See the doc string of `project-find-functions' for the general form
 of the project instance object.
@@ -28116,29 +28223,17 @@ With ARG non-nil, silently save all file-visiting 
buffers, then kill.
 If emacsclient was started with a list of filenames to edit, then
 only these files will be asked to be saved.
 
+When running Emacs as a daemon and with
+`server-stop-automatically' (which see) set to `kill-terminal' or
+`delete-frame', this function may call `save-buffers-kill-emacs'
+if there are no other active clients.
+
 (fn ARG)")
 (autoload 'server-stop-automatically "server" "\
-Automatically stop server as specified by ARG.
-
-If ARG is the symbol `empty', stop the server when it has no
-remaining clients, no remaining unsaved file-visiting buffers,
-and no running processes with a `query-on-exit' flag.
-
-If ARG is the symbol `delete-frame', ask the user when the last
-frame is deleted whether each unsaved file-visiting buffer must
-be saved and each running process with a `query-on-exit' flag
-can be stopped, and if so, stop the server itself.
+Automatically stop the Emacs server as specified by VALUE.
+This sets the variable `server-stop-automatically' (which see).
 
-If ARG is the symbol `kill-terminal', ask the user when the
-terminal is killed with \\[save-buffers-kill-terminal] whether each unsaved 
file-visiting
-buffer must be saved and each running process with a `query-on-exit'
-flag can be stopped, and if so, stop the server itself.
-
-Any other value of ARG will cause this function to signal an error.
-
-This function is meant to be called from the user init file.
-
-(fn ARG)")
+(fn VALUE)")
 (register-definition-prefixes "server" '("server-"))
 
 
@@ -32875,10 +32970,18 @@ FRAC should be the inverse of the fractional value; 
for example, a value of
 ;;; Generated autoloads from progmodes/typescript-ts-mode.el
 
 (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
-(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-ts-mode))
+(add-to-list 'auto-mode-alist '("\\.tsx\\'" . tsx-ts-mode))
+(autoload 'typescript-ts-base-mode "typescript-ts-mode" "\
+Major mode for editing TypeScript.
+
+(fn)" t)
 (autoload 'typescript-ts-mode "typescript-ts-mode" "\
 Major mode for editing TypeScript.
 
+(fn)" t)
+(autoload 'tsx-ts-mode "typescript-ts-mode" "\
+Major mode for editing TypeScript.
+
 (fn)" t)
 (register-definition-prefixes "typescript-ts-mode" '("typescript-ts-mode-"))
 
@@ -33606,6 +33709,195 @@ is \"www.fsf.co.uk\".
 (register-definition-prefixes "url-vars" '("url-"))
 
 
+;;; Generated autoloads from use-package/use-package.el
+
+(push (purecopy '(use-package 2 4 4)) package--builtin-versions)
+
+
+;;; Generated autoloads from use-package/use-package-bind-key.el
+
+(autoload 'use-package-autoload-keymap "use-package-bind-key" "\
+Load PACKAGE and bind key sequence invoking this function to KEYMAP-SYMBOL.
+Then simulate pressing the same key sequence a again, so that the
+next key pressed is routed to the newly loaded keymap.
+
+This function supports use-package's :bind-keymap keyword.  It
+works by binding the given key sequence to an invocation of this
+function for a particular keymap.  The keymap is expected to be
+defined by the package.  In this way, loading the package is
+deferred until the prefix key sequence is pressed.
+
+(fn KEYMAP-SYMBOL PACKAGE OVERRIDE)")
+(autoload 'use-package-normalize-binder "use-package-bind-key" "\
+
+
+(fn NAME KEYWORD ARGS)")
+(defalias 'use-package-normalize/:bind 'use-package-normalize-binder)
+(defalias 'use-package-normalize/:bind* 'use-package-normalize-binder)
+(defalias 'use-package-autoloads/:bind 'use-package-autoloads-mode)
+(defalias 'use-package-autoloads/:bind* 'use-package-autoloads-mode)
+(autoload 'use-package-handler/:bind "use-package-bind-key" "\
+
+
+(fn NAME KEYWORD ARGS REST STATE &optional BIND-MACRO)")
+(defalias 'use-package-normalize/:bind-keymap 'use-package-normalize-binder)
+(defalias 'use-package-normalize/:bind-keymap* 'use-package-normalize-binder)
+(autoload 'use-package-handler/:bind-keymap "use-package-bind-key" "\
+
+
+(fn NAME KEYWORD ARGS REST STATE &optional OVERRIDE)")
+(autoload 'use-package-handler/:bind-keymap* "use-package-bind-key" "\
+
+
+(fn NAME KEYWORD ARG REST STATE)")
+(register-definition-prefixes "use-package-bind-key" 
'("use-package-handler/:bind*"))
+
+
+;;; Generated autoloads from use-package/use-package-core.el
+
+(autoload 'use-package "use-package-core" "\
+Declare an Emacs package by specifying a group of configuration options.
+
+For the full documentation, see Info node `(use-package) top'.
+Usage:
+
+  (use-package package-name
+     [:keyword [option]]...)
+
+:init            Code to run before PACKAGE-NAME has been loaded.
+:config          Code to run after PACKAGE-NAME has been loaded.  Note that
+                 if loading is deferred for any reason, this code does not
+                 execute until the lazy load has occurred.
+:preface         Code to be run before everything except `:disabled'; this
+                 can be used to define functions for use in `:if', or that
+                 should be seen by the byte-compiler.
+
+:mode            Form to be added to `auto-mode-alist'.
+:magic           Form to be added to `magic-mode-alist'.
+:magic-fallback  Form to be added to `magic-fallback-mode-alist'.
+:interpreter     Form to be added to `interpreter-mode-alist'.
+
+:commands        Define autoloads for commands that will be defined by the
+                 package.  This is useful if the package is being lazily
+                 loaded, and you wish to conditionally call functions in your
+                 `:init' block that are defined in the package.
+:autoload        Similar to :commands, but it for no-interactive one.
+:hook            Specify hook(s) to attach this package to.
+
+:bind            Bind keys, and define autoloads for the bound commands.
+:bind*           Bind keys, and define autoloads for the bound commands,
+                 *overriding all minor mode bindings*.
+:bind-keymap     Bind a key prefix to an auto-loaded keymap defined in the
+                 package.  This is like `:bind', but for keymaps.
+:bind-keymap*    Like `:bind-keymap', but overrides all minor mode bindings
+
+:defer           Defer loading of a package -- this is implied when using
+                 `:commands', `:bind', `:bind*', `:mode', `:magic', `:hook',
+                 `:magic-fallback', or `:interpreter'.  This can be an integer,
+                 to force loading after N seconds of idle time, if the package
+                 has not already been loaded.
+:demand          Prevent the automatic deferred loading introduced by 
constructs
+                 such as `:bind' (see `:defer' for the complete list).
+
+:after           Delay the effect of the use-package declaration
+                 until after the named libraries have loaded.
+                 Before they have been loaded, no other keyword
+                 has any effect at all, and once they have been
+                 loaded it is as if `:after' was not specified.
+
+:if EXPR         Initialize and load only if EXPR evaluates to a non-nil value.
+:disabled        The package is ignored completely if this keyword is present.
+:defines         Declare certain variables to silence the byte-compiler.
+:functions       Declare certain functions to silence the byte-compiler.
+:load-path       Add to the `load-path' before attempting to load the package.
+:diminish        Support for diminish.el (if installed).
+:delight         Support for delight.el (if installed).
+:custom          Call `Custom-set' or `set-default' with each variable
+                 definition without modifying the Emacs `custom-file'.
+                 (compare with `custom-set-variables').
+:custom-face     Call `custom-set-faces' with each face definition.
+:ensure          Loads the package using package.el if necessary.
+:pin             Pin the package to an archive.
+
+(fn NAME &rest ARGS)" nil t)
+(function-put 'use-package 'lisp-indent-function 'defun)
+(register-definition-prefixes "use-package-core" '("use-package-"))
+
+
+;;; Generated autoloads from use-package/use-package-delight.el
+
+(autoload 'use-package-normalize/:delight "use-package-delight" "\
+Normalize arguments to delight.
+
+(fn NAME KEYWORD ARGS)")
+(autoload 'use-package-handler/:delight "use-package-delight" "\
+
+
+(fn NAME KEYWORD ARGS REST STATE)")
+(register-definition-prefixes "use-package-delight" 
'("use-package-normalize-delight"))
+
+
+;;; Generated autoloads from use-package/use-package-diminish.el
+
+(autoload 'use-package-normalize/:diminish "use-package-diminish" "\
+
+
+(fn NAME KEYWORD ARGS)")
+(autoload 'use-package-handler/:diminish "use-package-diminish" "\
+
+
+(fn NAME KEYWORD ARG REST STATE)")
+(register-definition-prefixes "use-package-diminish" 
'("use-package-normalize-diminish"))
+
+
+;;; Generated autoloads from use-package/use-package-ensure.el
+
+(autoload 'use-package-normalize/:ensure "use-package-ensure" "\
+
+
+(fn NAME KEYWORD ARGS)")
+(autoload 'use-package-handler/:ensure "use-package-ensure" "\
+
+
+(fn NAME KEYWORD ENSURE REST STATE)")
+(register-definition-prefixes "use-package-ensure" '("use-package-"))
+
+
+;;; Generated autoloads from use-package/use-package-ensure-system-package.el
+
+(push (purecopy '(use-package-ensure-system-package 0 2)) 
package--builtin-versions)
+(autoload 'use-package-normalize/:ensure-system-package 
"use-package-ensure-system-package" "\
+Turn ARGS into a list of conses of the form (PACKAGE-NAME . INSTALL-COMMAND).
+
+(fn NAME-SYMBOL KEYWORD ARGS)")
+(autoload 'use-package-handler/:ensure-system-package 
"use-package-ensure-system-package" "\
+Execute the handler for `:ensure-system-package' keyword in `use-package'.
+
+(fn NAME KEYWORD ARG REST STATE)")
+(register-definition-prefixes "use-package-ensure-system-package" 
'("use-package-ensure-system-package-"))
+
+
+;;; Generated autoloads from use-package/use-package-jump.el
+
+(autoload 'use-package-jump-to-package-form "use-package-jump" "\
+Attempt to find and jump to the `use-package' form that loaded PACKAGE.
+This will only find the form if that form actually required
+PACKAGE.  If PACKAGE was previously required then this function
+will jump to the file that originally required PACKAGE instead.
+
+(fn PACKAGE)" t)
+(register-definition-prefixes "use-package-jump" '("use-package-find-require"))
+
+
+;;; Generated autoloads from use-package/use-package-lint.el
+
+(autoload 'use-package-lint "use-package-lint" "\
+Check for errors in `use-package' declarations.
+For example, if the module's `:if' condition is met, but even
+with the specified `:load-path' the module cannot be found." t)
+(register-definition-prefixes "use-package-lint" 
'("use-package-lint-declaration"))
+
+
 ;;; Generated autoloads from userlock.el
 
 (put 'create-lockfiles 'safe-local-variable 'booleanp)
diff --git a/lisp/leim/quail/cyrillic.el b/lisp/leim/quail/cyrillic.el
index 9f85bc1823..1ebbea8eb0 100644
--- a/lisp/leim/quail/cyrillic.el
+++ b/lisp/leim/quail/cyrillic.el
@@ -1712,6 +1712,138 @@ as follows.
  ("/T" ?Ө)
  ("/Y" ?Ү))
 
+
+;; Chuvash layout based on russian-computer.
+(quail-define-package
+ "cyrillic-chuvash" "Chuvash" "CV" t
+ "Input method for cyrillic Chuvash with a postfix modifier.
+
+  А* -> Ӑ
+  а* -> ӑ
+  Е* -> Ӗ
+  Е* -> ӗ
+  С* -> Ҫ
+  с* -> ҫ
+  У* -> Ӳ
+  у* -> ӳ
+
+Doubling the postfix separates the letter and postfix
+"
+       nil t nil nil nil nil nil nil nil nil t)
+
+(quail-define-rules
+       ("1" ?1)
+       ("2" ?2)
+       ("3" ?3)
+       ("4" ?4)
+       ("5" ?5)
+       ("6" ?6)
+       ("7" ?7)
+       ("8" ?8)
+       ("9" ?9)
+       ("0" ?0)
+       ("-" ?-)
+       ("=" ?=)
+       ("|" ?/)
+       ("`" ?ё)
+       ("q" ?й)
+       ("w" ?ц)
+       ("e" ?у)
+       ("r" ?к)
+       ("t" ?е)
+       ("y" ?н)
+       ("u" ?г)
+       ("i" ?ш)
+       ("o" ?щ)
+       ("p" ?з)
+       ("[" ?х)
+       ("]" ?ъ)
+       ("a" ?ф)
+       ("s" ?ы)
+       ("d" ?в)
+       ("f" ?а)
+       ("g" ?п)
+       ("h" ?р)
+       ("j" ?о)
+       ("k" ?л)
+       ("l" ?д)
+       (";" ?ж)
+       ("'" ?э)
+       ("\\" ?\\)
+       ("z" ?я)
+       ("x" ?ч)
+       ("c" ?с)
+       ("v" ?м)
+       ("b" ?и)
+       ("n" ?т)
+       ("m" ?ь)
+       ("," ?б)
+       ("." ?ю)
+       ("/" ?.)
+       ("!" ?!)
+       ("@" ?\")
+       ("#" ?№)
+       ("$" ?\;)
+       ("%" ?%)
+       ("^" ?:)
+       ("&" ??)
+       ("*" ?*)
+       ("(" ?\()
+       (")" ?\))
+       ("_" ?_)
+       ("+" ?+)
+       ("~" ?Ё)
+       ("Q" ?Й)
+       ("W" ?Ц)
+       ("E" ?У)
+       ("R" ?К)
+       ("T" ?Е)
+       ("Y" ?Н)
+       ("U" ?Г)
+       ("I" ?Ш)
+       ("O" ?Щ)
+       ("P" ?З)
+       ("{" ?Х)
+       ("}" ?Ъ)
+       ("A" ?Ф)
+       ("S" ?Ы)
+       ("D" ?В)
+       ("F" ?А)
+       ("G" ?П)
+       ("H" ?Р)
+       ("J" ?О)
+       ("K" ?Л)
+       ("L" ?Д)
+       (":" ?Ж)
+       ("\"" ?Э)
+       ("|" ?|)
+       ("Z" ?Я)
+       ("X" ?Ч)
+       ("C" ?С)
+       ("V" ?М)
+       ("B" ?И)
+       ("N" ?Т)
+       ("M" ?Ь)
+       ("<" ?Б)
+       (">" ?Ю)
+       ("?" ?,)
+       ("F*" ?Ӑ)
+       ("f*" ?ӑ)
+       ("T*" ?Ӗ)
+       ("t*" ?ӗ)
+       ("C*" ?Ҫ)
+       ("c*" ?ҫ)
+       ("E*" ?Ӳ)
+       ("e*" ?ӳ)
+       ("F**" ["А*"])
+       ("f**" ["а*"])
+       ("T**" ["Е*"])
+       ("t**" ["е*"])
+       ("C**" ["С*"])
+       ("c**" ["с*"])
+       ("E**" ["У*"])
+       ("e**" ["у*"]))
+
 ;; Local Variables:
 ;; coding: utf-8
 ;; End:
diff --git a/lisp/mail/rmailsum.el b/lisp/mail/rmailsum.el
index b30c32aaff..d63e05f5fa 100644
--- a/lisp/mail/rmailsum.el
+++ b/lisp/mail/rmailsum.el
@@ -80,9 +80,14 @@ commands consecutively.  Filled by
 
 (defvar rmail-summary-message-parents-vector nil
   "Vector that holds a list of indices of parents for each message.
-Message A is parent to message B if the id of A appear in the
-References or In-reply-to fields of B, or if A is the first
-message with the same subject as B.  First element is ignored.")
+Message A is parent of message B if the id of A appears in the
+\"References\" or \"In-reply-to\" fields of B, or if A is the first
+message with the same \"Subject\" as B.  First element is ignored.")
+
+(defvar rmail-summary-message-descendants-vector nil
+  "Vector that holds the direct descendants of each message.
+This is the antipode of `rmail-summary-message-parents-vector'.
+First element is ignored.")
 
 (defvar rmail-summary-font-lock-keywords
   '(("^ *[0-9]+D.*" . font-lock-string-face)                   ; Deleted.
@@ -318,11 +323,13 @@ message with the same subject as B.  First element is 
ignored.")
 (defun rmail-summary-fill-message-ids-hash-table ()
   "Fill `rmail-summary-message-ids-hash-table'."
   (with-current-buffer rmail-buffer
-    (setq rmail-summary-message-ids-hash-table (make-hash-table :test 'equal 
:size 1024))
+    (setq rmail-summary-message-ids-hash-table
+          (make-hash-table :test 'equal :size 1024))
     (let ((msgnum 1))
       (while (<= msgnum rmail-total-messages)
        (let ((id (rmail-get-header "Message-ID" msgnum)))
-         (puthash id (cons (cons id msgnum) (gethash id 
rmail-summary-message-ids-hash-table))
+         (puthash id (cons (cons id msgnum)
+                            (gethash id rmail-summary-message-ids-hash-table))
                   rmail-summary-message-ids-hash-table))
        (setq msgnum (1+ msgnum))))))
 
@@ -331,14 +338,18 @@ message with the same subject as B.  First element is 
ignored.")
     (if header
        (split-string header "[ \f\t\n\r\v,;]+"))))
 
-(defun rmail-summary-fill-message-parents-vector ()
-  "Fill `rmail-summary-message-parents-vector'."
+(defun rmail-summary-fill-message-parents-and-descs-vectors ()
+  "Fill parents and descendats vectors for messages.
+This populates `rmail-summary-message-parents-vector'
+and `rmail-summary-message-descendants-vector'."
   (with-current-buffer rmail-buffer
     (rmail-summary-fill-message-ids-hash-table)
     (setq rmail-summary-subjects-hash-table
           (make-hash-table :test 'equal :size 1024))
     (setq rmail-summary-message-parents-vector
           (make-vector (1+ rmail-total-messages) nil))
+    (setq rmail-summary-message-descendants-vector
+          (make-vector (1+ rmail-total-messages) nil))
     (let ((msgnum 1))
       (while (<= msgnum rmail-total-messages)
        (let* ((parents nil)
@@ -346,18 +357,27 @@ message with the same subject as B.  First element is 
ignored.")
               (subj-cell (gethash subject rmail-summary-subjects-hash-table))
               (subj-par (assoc subject subj-cell))
               (refs (rmail-summary--split-header-field "References" msgnum))
-              (reply-to (rmail-summary--split-header-field "In-reply-to"
+              (reply-tos (rmail-summary--split-header-field "In-reply-to"
                                                             msgnum)))
          (if subj-par
-             (setq parents (cons (cdr subj-par) parents))
+             (progn
+               (setq parents (cons (cdr subj-par) nil))
+               (aset rmail-summary-message-descendants-vector (cdr subj-par)
+                     (cons msgnum
+                            (aref rmail-summary-message-descendants-vector
+                                  (cdr subj-par)))))
            (puthash subject (cons (cons subject msgnum) subj-cell)
                     rmail-summary-subjects-hash-table))
-         (dolist (id (append refs reply-to))
+         (dolist (id (append refs reply-tos))
            (let ((ent
                    (assoc id
                           (gethash id rmail-summary-message-ids-hash-table))))
-             (if ent
-                 (setq parents (cons (cdr ent) parents)))))
+             (when ent
+               (setq parents (cons (cdr ent) parents))
+               (aset rmail-summary-message-descendants-vector (cdr ent)
+                     (cons msgnum
+                            (aref rmail-summary-message-descendants-vector
+                                  (cdr ent)))))))
          (aset rmail-summary-message-parents-vector msgnum parents)
          (setq msgnum (1+ msgnum)))))))
 
@@ -387,20 +407,6 @@ the messages that are displayed."
   (interactive)
   (rmail-new-summary "All" '(rmail-summary) nil))
 
-(defun rmail-summary-direct-descendants (msgnum encountered-msgs)
-  "Find all direct descendants of MSGNUM, ignoring ENCOUNTERED-MSGS.
-Assumes `rmail-summary-message-parents-vector' is filled.  Ignores messages
-already ticked in ENCOUNTERED-MSGS."
-  (let (desc
-       (msg 1))
-    (while (<= msg rmail-total-messages)
-      (when (and
-            (not (aref encountered-msgs msg))
-            (memq msgnum (aref rmail-summary-message-parents-vector msg)))
-       (setq desc (cons msg desc)))
-      (setq msg (1+ msg)))
-    desc))
-
 (defun rmail-summary--walk-thread-message-recursively (msgnum encountered-msgs)
   "Add parents and descendants of message MSGNUM to ENCOUNTERED-MSGS, 
recursively."
   (unless (aref encountered-msgs msgnum)
@@ -412,7 +418,7 @@ already ticked in ENCOUNTERED-MSGS."
       (mapc walk-thread-msg
             (aref rmail-summary-message-parents-vector msgnum))
       (mapc walk-thread-msg
-            (rmail-summary-direct-descendants msgnum encountered-msgs)))))
+            (aref rmail-summary-message-descendants-vector msgnum)))))
 
 ;;;###autoload
 (defun rmail-summary-by-thread (&optional msgnum)
@@ -430,7 +436,7 @@ headers of the messages."
     (unless (and rmail-summary-message-parents-vector
                 (= (length rmail-summary-message-parents-vector)
                    (1+ rmail-total-messages)))
-      (rmail-summary-fill-message-parents-vector))
+      (rmail-summary-fill-message-parents-and-descs-vectors))
     (let ((enc-msgs (make-bool-vector (1+ rmail-total-messages) nil)))
       (rmail-summary--walk-thread-message-recursively msgnum enc-msgs)
       (rmail-new-summary (format "thread containing message %d" msgnum)
diff --git a/lisp/mh-e/mh-identity.el b/lisp/mh-e/mh-identity.el
index bcdf91299b..2507c67746 100644
--- a/lisp/mh-e/mh-identity.el
+++ b/lisp/mh-e/mh-identity.el
@@ -141,7 +141,7 @@ See `mh-identity-list'."
            (cons '("None")
                  (mapcar #'list (mapcar #'car mh-identity-list)))
            nil t default nil default))
-    (if (eq identity "None")
+    (if (equal identity "None")
         nil
       identity)))
 
diff --git a/lisp/minibuffer.el b/lisp/minibuffer.el
index a1153a98c4..a89f8191c0 100644
--- a/lisp/minibuffer.el
+++ b/lisp/minibuffer.el
@@ -1328,9 +1328,9 @@ pair of a group title string and a list of group 
candidate strings."
   :version "28.1")
 
 (defface completions-group-separator
-  '((t :inherit shadow :underline t))
+  '((t :inherit shadow :strike-through t))
   "Face used for the separator lines between the candidate groups."
-  :version "29.1")
+  :version "28.1")
 
 (defun completion--cycle-threshold (metadata)
   (let* ((cat (completion-metadata-get metadata 'category))
diff --git a/lisp/mouse-drag.el b/lisp/mouse-drag.el
index f515cc8aac..81b699c020 100644
--- a/lisp/mouse-drag.el
+++ b/lisp/mouse-drag.el
@@ -275,6 +275,7 @@ To test this function, evaluate:
         have-scrolled
         window-last-row
         col window-last-col
+         switch-frame-p
         (scroll-col-delta 0)
         ;; be conservative about allowing horizontal scrolling
         (col-scrolling-p (mouse-drag-should-do-col-scrolling)))
@@ -286,15 +287,21 @@ To test this function, evaluate:
       (setq track-mouse 'drag-dragging)
       (while (progn
               (setq event (read--potential-mouse-event)
-                    end (event-end event)
-                    row (cdr (posn-col-row end))
-                    col (car (posn-col-row end)))
-              (or (mouse-movement-p event)
-                  (eq (car-safe event) 'switch-frame)))
+                     switch-frame-p (eq (car-safe event) 'switch-frame))
+               ;; We want to skip switch-frame events and treat then
+               ;; as moves over a different window.  These events have
+               ;; no position spec, so all the posn-* accessor
+               ;; functions are likely to barf if passed such an
+               ;; event.
+               (or switch-frame-p
+                   (setq end (event-end event)
+                        row (cdr (posn-col-row end))
+                        col (car (posn-col-row end))))
+              (or (mouse-movement-p event) switch-frame-p))
        ;; Scroll if see if we're on the edge.
        ;; FIXME: should handle mouse-in-other window.
        (cond
-        ((not (eq start-window (posn-window end)))
+        ((or switch-frame-p (not (eq start-window (posn-window end))))
          t) ; wait for return to original window
         ((<= row 0) (mouse-drag-repeatedly-safe-scroll -1 0))
         ((>= row window-last-row) (mouse-drag-repeatedly-safe-scroll 1 0))
diff --git a/lisp/mouse.el b/lisp/mouse.el
index f72ab4fc64..095d30a285 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -105,6 +105,15 @@ point at the click position."
   :type 'boolean
   :version "22.1")
 
+(defcustom mouse-1-double-click-prefer-symbols nil
+  "If non-nil, double-clicking Mouse-1 attempts to select the symbol at click.
+
+If nil, the default, double-clicking Mouse-1 on a word-constituent
+character will select only the word at click location, which could
+select fewer characters than the symbol at click."
+  :type 'boolean
+  :version "30.1")
+
 (defcustom mouse-drag-and-drop-region-scroll-margin nil
   "If non-nil, the scroll margin inside a window when dragging text.
 If the mouse moves this many lines close to the top or bottom of
@@ -1800,10 +1809,17 @@ The region will be defined with mark and point."
 ;; Commands to handle xterm-style multiple clicks.
 (defun mouse-skip-word (dir)
   "Skip over word, over whitespace, or over identical punctuation.
+If `mouse-1-double-click-prefer-symbols' is non-nil, skip over symbol.
 If DIR is positive skip forward; if negative, skip backward."
   (let* ((char (following-char))
-        (syntax (char-to-string (char-syntax char))))
-    (cond ((string= syntax "w")
+        (syntax (char-to-string (char-syntax char)))
+         sym)
+    (cond ((and mouse-1-double-click-prefer-symbols
+                (setq sym (bounds-of-thing-at-point 'symbol)))
+           (goto-char (if (< dir 0)
+                          (car sym)
+                        (cdr sym))))
+          ((string= syntax "w")
           ;; Here, we can't use skip-syntax-forward/backward because
           ;; they don't pay attention to word-separating-categories,
           ;; and thus they will skip over a true word boundary.  So,
diff --git a/lisp/net/ange-ftp.el b/lisp/net/ange-ftp.el
index 6e17e417ea..9781ebf863 100644
--- a/lisp/net/ange-ftp.el
+++ b/lisp/net/ange-ftp.el
@@ -4498,6 +4498,25 @@ NEWNAME should be the name to give the new compressed or 
uncompressed file.")
 (put 'process-file 'ange-ftp 'ange-ftp-process-file)
 (put 'start-file-process 'ange-ftp 'ignore)
 (put 'shell-command 'ange-ftp 'ange-ftp-shell-command)
+
+;; Do not execute system information functions.
+(put 'file-system-info 'ange-ftp 'ignore)
+(put 'list-system-processes 'ange-ftp 'ignore)
+(put 'memory-info 'ange-ftp 'ignore)
+(put 'process-attributes 'ange-ftp 'ignore)
+
+;; There aren't ACLs.  `file-selinux-context' shall return '(nil nil
+;; nil nil) if the file is nonexistent, so we let the default file
+;; name handler do the job.
+(put 'file-acl 'ange-ftp 'ignore)
+;; (put 'file-selinux-context 'ange-ftp 'ignore)
+(put 'set-file-acl 'ange-ftp 'ignore)
+(put 'set-file-selinux-context 'ange-ftp 'ignore)
+
+;; There aren't file notifications.
+(put 'file-notify-add-watch 'ange-ftp 'ignore)
+(put 'file-notify-rm-watch 'ange-ftp 'ignore)
+(put 'file-notify-valid-p 'ange-ftp 'ignore)
 
 ;;; Define ways of getting at unmodified Emacs primitives,
 ;;; turning off our handler.
diff --git a/lisp/net/rcirc.el b/lisp/net/rcirc.el
index 29957a62d0..81a572250a 100644
--- a/lisp/net/rcirc.el
+++ b/lisp/net/rcirc.el
@@ -1396,10 +1396,10 @@ inserted."
   (interactive "P")
   (rcirc-format "\^_" replace))
 
-(defun rcirc-format-strike-trough (replace)
-  "Insert strike-trough formatting.
+(defun rcirc-format-strike-through (replace)
+  "Insert strike-through formatting.
 If REPLACE is non-nil or a prefix argument is given, any prior
-formatting will be replaced before the strike-trough formatting
+formatting will be replaced before the strike-through formatting
 is inserted."
   (interactive "P")
   (rcirc-format "\^^" replace))
@@ -1421,7 +1421,7 @@ inserted."
   "C-c C-f C-b" #'rcirc-format-bold
   "C-c C-f C-i" #'rcirc-format-italic
   "C-c C-f C-u" #'rcirc-format-underline
-  "C-c C-f C-s" #'rcirc-format-strike-trough
+  "C-c C-f C-s" #'rcirc-format-strike-through
   "C-c C-f C-f" #'rcirc-format-fixed-width
   "C-c C-f C-t" #'rcirc-format-fixed-width ;as in AucTeX
   "C-c C-f C-d" #'rcirc-unformat
@@ -1807,7 +1807,7 @@ extracted."
   "C-c C-f C-b" #'rcirc-format-bold
   "C-c C-f C-i" #'rcirc-format-italic
   "C-c C-f C-u" #'rcirc-format-underline
-  "C-c C-f C-s" #'rcirc-format-strike-trough
+  "C-c C-f C-s" #'rcirc-format-strike-through
   "C-c C-f C-f" #'rcirc-format-fixed-width
   "C-c C-f C-t" #'rcirc-format-fixed-width ;as in AucTeX
   "C-c C-f C-d" #'rcirc-unformat
@@ -2371,9 +2371,11 @@ This function does not alter the INPUT string."
   "C-c C-@"   #'rcirc-next-active-buffer
   "C-c C-SPC" #'rcirc-next-active-buffer)
 
-(defcustom rcirc-track-abbrevate-flag t
+(define-obsolete-variable-alias 'rcirc-track-abbrevate-flag
+  'rcirc-track-abbreviate-flag "30.1")
+(defcustom rcirc-track-abbreviate-flag t
   "Non-nil means `rcirc-track-minor-mode' should abbreviate names."
-  :version "28.1"
+  :version "30.1"
   :type 'boolean)
 
 ;;;###autoload
@@ -2559,7 +2561,7 @@ activity.  Only run if the buffer is not visible and
     (funcall rcirc-channel-filter
              (replace-regexp-in-string
               "@.*?\\'" ""
-              (or (and rcirc-track-abbrevate-flag
+              (or (and rcirc-track-abbreviate-flag
                        rcirc-short-buffer-name)
                   (buffer-name))))))
 
@@ -4002,6 +4004,9 @@ PROCESS is the process object for the current connection."
                      (string-equal (downcase (car setting)) parameter))
            return (cadr setting)))
 
+(define-obsolete-function-alias 'rcirc-format-strike-trough
+  'rcirc-format-strike-through "30.1")
+
 (provide 'rcirc)
 
 ;;; rcirc.el ends here
diff --git a/lisp/net/tramp-archive.el b/lisp/net/tramp-archive.el
index 9c1e78d6b0..49b0c0bb6b 100644
--- a/lisp/net/tramp-archive.el
+++ b/lisp/net/tramp-archive.el
@@ -215,11 +215,18 @@ It must be supported by libarchive(3).")
 ;; In older Emacs (prior 27.1), `tramp-archive-autoload-file-name-regexp'
 ;; is not autoloaded.  So we cannot expect it to be known in
 ;; tramp-loaddefs.el.  But it exists, when tramp-archive.el is loaded.
+;; We must wrap it into `eval-when-compile'.  Otherwise, there could
+;; be an "Eager macro-expansion failure" when unloading/reloading Tramp.
 ;;;###tramp-autoload
 (defconst tramp-archive-file-name-regexp
-  (ignore-errors (tramp-archive-autoload-file-name-regexp))
+  (eval-when-compile (ignore-errors (tramp-archive-autoload-file-name-regexp)))
   "Regular expression matching archive file names.")
 
+;; The value above is nil for Emacs 26.  Set it now.
+(if (<= emacs-major-version 26)
+    (setq tramp-archive-file-name-regexp
+         (ignore-errors (tramp-archive-autoload-file-name-regexp))))
+
 ;;;###tramp-autoload
 (defconst tramp-archive-method "archive"
   "Method name for archives in GVFS.")
diff --git a/lisp/net/tramp-crypt.el b/lisp/net/tramp-crypt.el
index fa40f96818..249b3fcd4d 100644
--- a/lisp/net/tramp-crypt.el
+++ b/lisp/net/tramp-crypt.el
@@ -318,7 +318,7 @@ connection if a previous connection has died for some 
reason."
       (process-put p 'vector vec)
       (set-process-query-on-exit-flag p nil)))
 
-  ;; The following operations must be performed w/o
+  ;; The following operations must be performed without
   ;; `tramp-crypt-file-name-handler'.
   (let* (tramp-crypt-enabled
         ;; Don't check for a proper method.
diff --git a/lisp/net/tramp-gvfs.el b/lisp/net/tramp-gvfs.el
index 73f773e8f4..da7641774f 100644
--- a/lisp/net/tramp-gvfs.el
+++ b/lisp/net/tramp-gvfs.el
@@ -690,7 +690,7 @@ It has been changed in GVFS 1.14.")
     ("gvfs-set-attribute" . "set"))
   "List of cons cells, mapping \"gvfs-<command>\" to \"gio <command>\".")
 
-;; <http://www.pygtk.org/docs/pygobject/gio-constants.html>
+;; <https://www.pygtk.org/docs/pygobject/gio-constants.html>
 (eval-and-compile
   (defconst tramp-gvfs-file-attributes
     '("name"
diff --git a/lisp/net/tramp-sh.el b/lisp/net/tramp-sh.el
index df5800f4e9..6087f16431 100644
--- a/lisp/net/tramp-sh.el
+++ b/lisp/net/tramp-sh.el
@@ -3431,6 +3431,7 @@ implementation will be used."
             (signal (car err) (cdr err)))))
 
       ;; Impossible to copy.  Trigger `file-missing' error.
+      (delete-file tmpfile)
       (setq tmpfile nil))))
 
 (defun tramp-sh-handle-write-region
diff --git a/lisp/net/tramp-smb.el b/lisp/net/tramp-smb.el
index c720b33b5f..cd73b9b8ec 100644
--- a/lisp/net/tramp-smb.el
+++ b/lisp/net/tramp-smb.el
@@ -279,7 +279,7 @@ See `tramp-actions-before-shell' for more info.")
     (lock-file . tramp-handle-lock-file)
     (make-auto-save-file-name . tramp-handle-make-auto-save-file-name)
     (make-directory . tramp-smb-handle-make-directory)
-    (make-directory-internal . tramp-smb-handle-make-directory-internal)
+    (make-directory-internal . ignore)
     (make-lock-file-name . tramp-handle-make-lock-file-name)
     (make-nearby-temp-file . tramp-handle-make-nearby-temp-file)
     (make-process . ignore)
@@ -1186,12 +1186,21 @@ PRESERVE-UID-GID and PRESERVE-EXTENDED-ATTRIBUTES are 
completely ignored."
        (make-directory ldir parents))
       ;; Just do it.
       (when (file-directory-p ldir)
-       (make-directory-internal dir))
+       (tramp-smb-send-command
+        v (if (tramp-smb-get-cifs-capabilities v)
+              (format "posix_mkdir %s %o"
+                      (tramp-smb-shell-quote-localname v) (default-file-modes))
+            (format "mkdir %s" (tramp-smb-shell-quote-localname v))))
+       ;; We must also flush the cache of the directory, because
+       ;; `file-attributes' reads the values from there.
+       (tramp-flush-file-properties v localname))
       (unless (file-directory-p dir)
        (tramp-error v 'file-error "Couldn't make directory %s" dir)))))
 
+;; This is not used anymore.
 (defun tramp-smb-handle-make-directory-internal (directory)
   "Like `make-directory-internal' for Tramp files."
+  (declare (obsolete nil "29.1"))
   (setq directory (directory-file-name (expand-file-name directory)))
   (unless (file-name-absolute-p directory)
     (setq directory (expand-file-name directory default-directory)))
diff --git a/lisp/net/tramp.el b/lisp/net/tramp.el
index 9b7117cb87..ca8963fbf5 100644
--- a/lisp/net/tramp.el
+++ b/lisp/net/tramp.el
@@ -2605,12 +2605,14 @@ Must be handled by the callers."
              file-selinux-context file-symlink-p file-truename
              file-writable-p find-backup-file-name get-file-buffer
              insert-directory insert-file-contents load
-             make-directory make-directory-internal set-file-acl
-             set-file-modes set-file-selinux-context set-file-times
+             make-directory set-file-acl set-file-modes
+             set-file-selinux-context set-file-times
              substitute-in-file-name unhandled-file-name-directory
              vc-registered
              ;; Emacs 27+ only.
              file-system-info
+             ;; Emacs 28- only.
+             make-directory-internal
              ;; Emacs 28+ only.
              file-locked-p lock-file make-lock-file-name unlock-file
              ;; Emacs 29+ only.
diff --git a/lisp/org/ChangeLog.1 b/lisp/org/ChangeLog.1
index f79d8bf674..4f51c6a1eb 100644
--- a/lisp/org/ChangeLog.1
+++ b/lisp/org/ChangeLog.1
@@ -1867,7 +1867,7 @@
 
        * org.el: Use
        `org-define-obsolete-{function,variable}-alias´instead of
-       `define-obsolate{function,variable}-alias´.
+       `define-obsolete-{function,variable}-alias´.
 
        * org-compat.el (user-error): Defalias to `error´ for Emacsen that
        don't have it.
diff --git a/lisp/org/ob-R.el b/lisp/org/ob-R.el
index f68b5b44e4..b7f96a179a 100644
--- a/lisp/org/ob-R.el
+++ b/lisp/org/ob-R.el
@@ -241,11 +241,11 @@ This function is called by `org-babel-execute-src-block'."
 (defun org-babel-R-assign-elisp (name value colnames-p rownames-p)
   "Construct R code assigning the elisp VALUE to a variable named NAME."
   (if (listp value)
-      (let* ((lengths (mapcar 'length (cl-remove-if-not 'sequencep value)))
+      (let* ((lengths (mapcar 'length (cl-remove-if-not 'listp value)))
             (max (if lengths (apply 'max lengths) 0))
             (min (if lengths (apply 'min lengths) 0)))
         ;; Ensure VALUE has an orgtbl structure (depth of at least 2).
-        (unless (listp (car value)) (setq value (list value)))
+        (unless (listp (car value)) (setq value (mapcar 'list value)))
        (let ((file (orgtbl-to-tsv value '(:fmt org-babel-R-quote-tsv-field)))
              (header (if (or (eq (nth 1 value) 'hline) colnames-p)
                          "TRUE" "FALSE"))
diff --git a/lisp/org/ob-clojure.el b/lisp/org/ob-clojure.el
index b424cf48ff..b045b4e6e5 100644
--- a/lisp/org/ob-clojure.el
+++ b/lisp/org/ob-clojure.el
@@ -248,8 +248,8 @@ or set the `:backend' header argument"))))
                                "value")))
                result0)))
       (ob-clojure-string-or-list
-       ;; Filter out s-expressions that return `nil' (string "nil"
-       ;; from nrepl eval) or comment forms (actual `nil' from nrepl)
+       ;; Filter out s-expressions that return nil (string "nil"
+       ;; from nrepl eval) or comment forms (actual nil from nrepl)
        (reverse (delete "" (mapcar (lambda (r)
                                     (replace-regexp-in-string "nil" "" (or r 
"")))
                                   result0)))))))
diff --git a/lisp/org/ob-comint.el b/lisp/org/ob-comint.el
index e8d8367076..064ba94464 100644
--- a/lisp/org/ob-comint.el
+++ b/lisp/org/ob-comint.el
@@ -117,6 +117,14 @@ or user `keyboard-quit' during execution of body."
         (goto-char (process-mark (get-buffer-process (current-buffer))))
         (insert dangling-text)
 
+         ;; Replace partially supplied input lines.
+         ;; This is needed when output filter spits partial lines that
+         ;; do not include a full prompt at a time.
+         (setq string-buffer
+               (replace-regexp-in-string
+                comint-prompt-regexp
+                ,org-babel-comint-prompt-separator
+                string-buffer))
         ;; remove echo'd FULL-BODY from input
         (when (and ,remove-echo ,full-body
                    (string-match
diff --git a/lisp/org/ob-core.el b/lisp/org/ob-core.el
index 5b78ee946f..f69538f78c 100644
--- a/lisp/org/ob-core.el
+++ b/lisp/org/ob-core.el
@@ -2709,7 +2709,9 @@ specified as an an \"attachment:\" style link."
                 ((and 'attachment (guard in-attach-dir)) "attachment")
                 (_ "file"))
               (if (and request-attachment in-attach-dir)
-                  (file-relative-name result-file-name)
+                  (file-relative-name
+                   result-file-name
+                   (file-name-as-directory attach-dir))
                (if (and default-directory
                         base-file-name same-directory?)
                    (if (eq org-link-file-path-type 'adaptive)
diff --git a/lisp/org/ob-octave.el b/lisp/org/ob-octave.el
index b0a7767ec3..8953b67513 100644
--- a/lisp/org/ob-octave.el
+++ b/lisp/org/ob-octave.el
@@ -91,7 +91,7 @@ end")
                                 (list
                                  "set (0, \"defaultfigurevisible\", \"off\");"
                                  full-body
-                                 (format "print -dpng %s" gfx-file))
+                                 (format "print -dpng %S\nans=%S" gfx-file 
gfx-file))
                                 "\n")
                    full-body)
                  result-type matlabp)))
diff --git a/lisp/org/oc-bibtex.el b/lisp/org/oc-bibtex.el
index 33fba8c401..4d2297a829 100644
--- a/lisp/org/oc-bibtex.el
+++ b/lisp/org/oc-bibtex.el
@@ -6,18 +6,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/lisp/org/ol.el b/lisp/org/ol.el
index cd52e9cf4d..3ae8f88755 100644
--- a/lisp/org/ol.el
+++ b/lisp/org/ol.el
@@ -1488,9 +1488,9 @@ If the link is in hidden text, expose it."
 
 (defun org-link-descriptive-ensure ()
   "Toggle the literal or descriptive display of links in current buffer if 
needed."
-  (if org-link-descriptive
-      (org-fold-core-set-folding-spec-property (car 
org-link--link-folding-spec) :visible nil)
-    (org-fold-core-set-folding-spec-property (car org-link--link-folding-spec) 
:visible t)))
+  (org-fold-core-set-folding-spec-property
+   (car org-link--link-folding-spec)
+   :visible (not org-link-descriptive)))
 
 ;;;###autoload
 (defun org-toggle-link-display ()
diff --git a/lisp/org/org-clock.el b/lisp/org/org-clock.el
index f28805d5e6..02cddddb30 100644
--- a/lisp/org/org-clock.el
+++ b/lisp/org/org-clock.el
@@ -3049,53 +3049,58 @@ PROPERTIES: The list properties specified in the 
`:properties' parameter
   "If this is a CLOCK line, update it and return t.
 Otherwise, return nil."
   (interactive)
-  (save-excursion
-    (beginning-of-line 1)
-    (skip-chars-forward " \t")
-    (when (looking-at org-clock-string)
-      (let ((re (concat "[ \t]*" org-clock-string
-                       " *[[<]\\([^]>]+\\)[]>]\\(-+[[<]\\([^]>]+\\)[]>]"
-                       "\\([ \t]*=>.*\\)?\\)?"))
-           ts te h m s neg)
-       (cond
-        ((not (looking-at re))
-         nil)
-        ((not (match-end 2))
-         (when (and (equal (marker-buffer org-clock-marker) (current-buffer))
-                    (> org-clock-marker (point))
-                     (<= org-clock-marker (line-end-position)))
-           ;; The clock is running here
-           (setq org-clock-start-time
-                 (org-time-string-to-time (match-string 1)))
-           (org-clock-update-mode-line)))
-        (t
-          ;; Prevent recursive call from `org-timestamp-change'.
-          (cl-letf (((symbol-function 'org-clock-update-time-maybe) #'ignore))
-            ;; Update timestamps.
-            (save-excursion
-              (goto-char (match-beginning 1)) ; opening timestamp
-              (save-match-data (org-timestamp-change 0 'day)))
+  (let ((origin (point))) ;; `save-excursion' may not work when deleting.
+    (save-excursion
+      (beginning-of-line 1)
+      (skip-chars-forward " \t")
+      (when (looking-at org-clock-string)
+        (let ((re (concat "[ \t]*" org-clock-string
+                         " *[[<]\\([^]>]+\\)[]>]\\(-+[[<]\\([^]>]+\\)[]>]"
+                         "\\([ \t]*=>.*\\)?\\)?"))
+             ts te h m s neg)
+          (cond
+          ((not (looking-at re))
+           nil)
+          ((not (match-end 2))
+           (when (and (equal (marker-buffer org-clock-marker) (current-buffer))
+                      (> org-clock-marker (point))
+                       (<= org-clock-marker (line-end-position)))
+             ;; The clock is running here
+             (setq org-clock-start-time
+                   (org-time-string-to-time (match-string 1)))
+             (org-clock-update-mode-line)))
+          (t
+            ;; Prevent recursive call from `org-timestamp-change'.
+            (cl-letf (((symbol-function 'org-clock-update-time-maybe) 
#'ignore))
+              ;; Update timestamps.
+              (save-excursion
+                (goto-char (match-beginning 1)) ; opening timestamp
+                (save-match-data (org-timestamp-change 0 'day)))
+              ;; Refresh match data.
+              (looking-at re)
+              (save-excursion
+                (goto-char (match-beginning 3)) ; closing timestamp
+                (save-match-data (org-timestamp-change 0 'day))))
             ;; Refresh match data.
             (looking-at re)
-            (save-excursion
-              (goto-char (match-beginning 3)) ; closing timestamp
-              (save-match-data (org-timestamp-change 0 'day))))
-          ;; Refresh match data.
-          (looking-at re)
-          (and (match-end 4) (delete-region (match-beginning 4) (match-end 4)))
-          (end-of-line 1)
-          (setq ts (match-string 1)
-                te (match-string 3))
-          (setq s (- (org-time-string-to-seconds te)
-                    (org-time-string-to-seconds ts))
-                neg (< s 0)
-                s (abs s)
-                h (floor (/ s 3600))
-                s (- s (* 3600 h))
-                m (floor (/ s 60))
-                s (- s (* 60 s)))
-         (insert " => " (format (if neg "-%d:%02d" "%2d:%02d") h m))
-         t))))))
+            (and (match-end 4) (delete-region (match-beginning 4) (match-end 
4)))
+            (end-of-line 1)
+            (setq ts (match-string 1)
+                  te (match-string 3))
+            (setq s (- (org-time-string-to-seconds te)
+                      (org-time-string-to-seconds ts))
+                  neg (< s 0)
+                  s (abs s)
+                  h (floor (/ s 3600))
+                  s (- s (* 3600 h))
+                  m (floor (/ s 60))
+                  s (- s (* 60 s)))
+           (insert " => " (format (if neg "-%d:%02d" "%2d:%02d") h m))
+           t)))))
+    ;; Move back to initial position, but never beyond updated
+    ;; clock.
+    (unless (< (point) origin)
+      (goto-char origin))))
 
 (defun org-clock-save ()
   "Persist various clock-related data to disk.
diff --git a/lisp/org/org-element.el b/lisp/org/org-element.el
index 48ede9c528..71c242ea65 100644
--- a/lisp/org/org-element.el
+++ b/lisp/org/org-element.el
@@ -5295,6 +5295,7 @@ indentation removed from its contents."
 ;; `org-element--cache-diagnostics-ring-size', 
`org-element--cache-map-statistics',
 ;; `org-element--cache-map-statistics-threshold'.
 
+;;;###autoload
 (defvar org-element-use-cache t
   "Non-nil when Org parser should cache its results.")
 
@@ -5717,7 +5718,11 @@ This function assumes `org-element--headline-cache' is a 
valid AVL tree."
               ;; `combine-change-calls' because the buffer is potentially
               ;; changed without notice (the change will be registered
               ;; after exiting the `combine-change-calls' body though).
-              (memq #'org-element--cache-after-change 
after-change-functions))))))
+              (catch :inhibited
+                (org-fold-core-cycle-over-indirect-buffers
+                  (unless (memq #'org-element--cache-after-change 
after-change-functions)
+                    (throw :inhibited nil)))
+                t))))))
 
 ;; FIXME: Remove after we establish that hashing is effective.
 (defun org-element-cache-hash-show-statistics ()
diff --git a/lisp/org/org-fold-core.el b/lisp/org/org-fold-core.el
index be600f8a0c..ffa689d4fa 100644
--- a/lisp/org/org-fold-core.el
+++ b/lisp/org/org-fold-core.el
@@ -497,7 +497,7 @@ hanging around."
   (declare (debug (form body)) (indent 0))
   `(let (buffers dead-properties)
      (if (and (not (buffer-base-buffer))
-              (not (eq (current-buffer) (car 
org-fold-core--indirect-buffers))))
+              (not (memq (current-buffer) org-fold-core--indirect-buffers)))
          ;; We are in base buffer with `org-fold-core--indirect-buffers' value 
from
          ;; different buffer.  This can happen, for example, when
          ;; org-capture copies local variables into *Capture* buffer.
@@ -930,6 +930,8 @@ are provided.
 
 If FROM is non-nil and TO is nil, search the folded regions at FROM.
 
+When both FROM and TO are nil, search folded regions in the whole buffer.
+
 When SPECS is non-nil it should be a list of folding specs or a symbol.
 Only return the matching fold types.
 
@@ -946,6 +948,9 @@ WITH-MARKERS must be nil when RELATIVE is non-nil."
   (unless (listp specs) (setq specs (list specs)))
   (let (regions region mk-region)
     (org-with-wide-buffer
+     (when (and (not from) (not to))
+       (setq from (point-min)
+             to (point-max)))
      (when (and from (not to)) (setq to (point-max)))
      (when (and from (< from (point-min))) (setq from (point-min)))
      (when (and to (> to (point-max))) (setq to (point-max)))
@@ -1058,7 +1063,7 @@ means that the buffer should stay alive during the 
operation,
 because otherwise all these markers will point to nowhere."
   (declare (debug (form body)) (indent 1))
   (org-with-gensyms (regions)
-    `(let* ((,regions ,(org-fold-core-get-regions :with-markers use-markers)))
+    `(let* ((,regions (org-fold-core-get-regions :with-markers ,use-markers)))
        (unwind-protect (progn ,@body)
          (org-fold-core-regions ,regions :override t :clean-markers t)))))
 
diff --git a/lisp/org/org-footnote.el b/lisp/org/org-footnote.el
index aedd413351..ac78360aef 100644
--- a/lisp/org/org-footnote.el
+++ b/lisp/org/org-footnote.el
@@ -851,9 +851,12 @@ to `org-footnote-section'.  Inline definitions are 
ignored."
                            (format "[fn:%s] DEFINITION NOT FOUND." label))
                        "\n"))))
          ;; Insert un-referenced footnote definitions at the end.
-         (pcase-dolist (`(,label . ,definition) definitions)
-           (unless (member label inserted)
-             (insert "\n" definition "\n")))))))))
+          ;; Combine all insertions into one to create a single cache
+          ;; update call.
+          (combine-change-calls (point) (point)
+           (pcase-dolist (`(,label . ,definition) definitions)
+             (unless (member label inserted)
+               (insert "\n" definition "\n"))))))))))
 
 (defun org-footnote-normalize ()
   "Turn every footnote in buffer into a numbered one."
diff --git a/lisp/org/org-persist.el b/lisp/org/org-persist.el
index 108292f1e9..6ccf357784 100644
--- a/lisp/org/org-persist.el
+++ b/lisp/org/org-persist.el
@@ -134,7 +134,7 @@
 ;; from the persistent storage at the end of Emacs session.  The
 ;; expiry condition can be set when saving/registering data
 ;; containers.  The expirty condition can be `never' - data will never
-;; expire; `nil' - data will expire at the end of current Emacs session;
+;; expire; nil - data will expire at the end of current Emacs session;
 ;; a number - data will expire after the number days from last access;
 ;; a function - data will expire if the function, called with a single
 ;; argument - collection, returns non-nil.
@@ -161,7 +161,7 @@
 (declare-function org-at-heading-p "org" (&optional invisible-not-ok))
 
 
-(defconst org-persist--storage-version "2.5"
+(defconst org-persist--storage-version "2.7"
   "Persistent storage layout version.")
 
 (defgroup org-persist nil
@@ -222,8 +222,11 @@ function will be called with a single argument - 
collection."
 (defconst org-persist-index-file "index"
   "File name used to store the data index.")
 
-(defvar org-persist-disable-when-emacs-Q t
-  "Disable persistence when Emacs is called with -Q command line arg.")
+(defvar org-persist--disable-when-emacs-Q t
+  "Disable persistence when Emacs is called with -Q command line arg.
+When non-nil, this sets `org-persist-directory' to temporary directory.
+
+This variable must be set before loading org-persist library.")
 
 (defvar org-persist-before-write-hook nil
   "Abnormal hook ran before saving data.
@@ -662,12 +665,13 @@ COLLECTION is the plist holding data collection."
              (file-copy (org-file-name-concat
                          org-persist-directory
                          (format "%s-%s.%s" persist-file (md5 path) ext))))
-        (unless (file-exists-p (file-name-directory file-copy))
-          (make-directory (file-name-directory file-copy) t))
-        (if (org--should-fetch-remote-resource-p path)
-            (url-copy-file path file-copy 'overwrite)
-          (error "The remote resource %S is considered unsafe, and will not be 
downloaded."
-                 path))
+        (unless (file-exists-p file-copy)
+          (unless (file-exists-p (file-name-directory file-copy))
+            (make-directory (file-name-directory file-copy) t))
+          (if (org--should-fetch-remote-resource-p path)
+              (url-copy-file path file-copy 'overwrite)
+            (error "The remote resource %S is considered unsafe, and will not 
be downloaded."
+                   path)))
         (format "%s-%s.%s" persist-file (md5 path) ext)))))
 
 (defun org-persist-write:index (container _)
@@ -771,43 +775,39 @@ ASSOCIATED can be a plist, a buffer, or a string.
 A buffer is treated as (:buffer ASSOCIATED).
 A string is treated as (:file ASSOCIATED).
 When LOAD? is non-nil, load the data instead of reading."
+  (unless org-persist--index (org-persist--load-index))
   (setq associated (org-persist--normalize-associated associated))
   (setq container (org-persist--normalize-container container))
-  (unless (and org-persist-disable-when-emacs-Q
-               ;; FIXME: This is relying on undocumented fact that
-               ;; Emacs sets `user-init-file' to nil when loaded with
-               ;; "-Q" argument.
-               (not user-init-file))
-    (let* ((collection (org-persist--find-index `(:container ,container 
:associated ,associated)))
-           (persist-file
-            (when collection
-              (org-file-name-concat
-               org-persist-directory
-               (plist-get collection :persist-file))))
-           (data nil))
-      (when (and collection
-                 (file-exists-p persist-file)
-                 (or (not (plist-get collection :expiry)) ; current session
-                     (not (org-persist--gc-expired-p
-                         (plist-get collection :expiry) collection)))
-                 (or (not hash-must-match)
-                     (and (plist-get associated :hash)
-                          (equal (plist-get associated :hash)
-                                 (plist-get (plist-get collection :associated) 
:hash)))))
-        (unless (seq-find (lambda (v)
-                            (run-hook-with-args-until-success 
'org-persist-before-read-hook v associated))
-                          (plist-get collection :container))
-          (setq data (or (gethash persist-file org-persist--write-cache)
-                         (org-persist--read-elisp-file persist-file)))
-          (when data
-            (cl-loop for container in (plist-get collection :container)
-                     with result = nil
-                     do
-                     (if load?
-                         (push (org-persist-load:generic container (alist-get 
container data nil nil #'equal) collection) result)
-                       (push (org-persist-read:generic container (alist-get 
container data nil nil #'equal) collection) result))
-                     (run-hook-with-args 'org-persist-after-read-hook 
container associated)
-                     finally return (if (= 1 (length result)) (car result) 
result))))))))
+  (let* ((collection (org-persist--find-index `(:container ,container 
:associated ,associated)))
+         (persist-file
+          (when collection
+            (org-file-name-concat
+             org-persist-directory
+             (plist-get collection :persist-file))))
+         (data nil))
+    (when (and collection
+               (file-exists-p persist-file)
+               (or (not (plist-get collection :expiry)) ; current session
+                   (not (org-persist--gc-expired-p
+                       (plist-get collection :expiry) collection)))
+               (or (not hash-must-match)
+                   (and (plist-get associated :hash)
+                        (equal (plist-get associated :hash)
+                               (plist-get (plist-get collection :associated) 
:hash)))))
+      (unless (seq-find (lambda (v)
+                          (run-hook-with-args-until-success 
'org-persist-before-read-hook v associated))
+                        (plist-get collection :container))
+        (setq data (or (gethash persist-file org-persist--write-cache)
+                       (org-persist--read-elisp-file persist-file)))
+        (when data
+          (cl-loop for container in (plist-get collection :container)
+                   with result = nil
+                   do
+                   (if load?
+                       (push (org-persist-load:generic container (alist-get 
container data nil nil #'equal) collection) result)
+                     (push (org-persist-read:generic container (alist-get 
container data nil nil #'equal) collection) result))
+                   (run-hook-with-args 'org-persist-after-read-hook container 
associated)
+                   finally return (if (= 1 (length result)) (car result) 
result)))))))
 
 (defun org-persist-load (container &optional associated hash-must-match)
   "Load CONTAINER data for ASSOCIATED.
@@ -843,55 +843,66 @@ The return value is nil when writing fails and the 
written value (as
 returned by `org-persist-read') on success.
 When IGNORE-RETURN is non-nil, just return t on success without calling
 `org-persist-read'."
-  (unless (and org-persist-disable-when-emacs-Q
-               ;; FIXME: This is relying on undocumented fact that
-               ;; Emacs sets `user-init-file' to nil when loaded with
-               ;; "-Q" argument.
-               (not user-init-file))
-    (setq associated (org-persist--normalize-associated associated))
-    ;; Update hash
-    (when (and (plist-get associated :file)
-               (plist-get associated :hash)
-               (get-file-buffer (plist-get associated :file)))
-      (setq associated (org-persist--normalize-associated (get-file-buffer 
(plist-get associated :file)))))
-    (let ((collection (org-persist--get-collection container associated)))
-      (setf collection (plist-put collection :associated associated))
-      (unless (seq-find (lambda (v)
-                          (run-hook-with-args-until-success 
'org-persist-before-write-hook v associated))
-                        (plist-get collection :container))
-        (when (or (file-exists-p org-persist-directory) 
(org-persist--save-index))
-          (let ((file (org-file-name-concat org-persist-directory (plist-get 
collection :persist-file)))
-                (data (mapcar (lambda (c) (cons c (org-persist-write:generic c 
collection)))
-                              (plist-get collection :container))))
-            (puthash file data org-persist--write-cache)
-            (org-persist--write-elisp-file file data)
-            (or ignore-return (org-persist-read container associated))))))))
+  (setq associated (org-persist--normalize-associated associated))
+  ;; Update hash
+  (when (and (plist-get associated :file)
+             (plist-get associated :hash)
+             (get-file-buffer (plist-get associated :file)))
+    (setq associated (org-persist--normalize-associated (get-file-buffer 
(plist-get associated :file)))))
+  (let ((collection (org-persist--get-collection container associated)))
+    (setf collection (plist-put collection :associated associated))
+    (unless (or
+             ;; Prevent data leakage from encrypted files.
+             ;; We do it in somewhat paranoid manner and do not
+             ;; allow anything related to encrypted files to be
+             ;; written.
+             (and (plist-get associated :file)
+                  (string-match-p epa-file-name-regexp (plist-get associated 
:file)))
+             (seq-find (lambda (v)
+                         (run-hook-with-args-until-success 
'org-persist-before-write-hook v associated))
+                       (plist-get collection :container)))
+      (when (or (file-exists-p org-persist-directory) 
(org-persist--save-index))
+        (let ((file (org-file-name-concat org-persist-directory (plist-get 
collection :persist-file)))
+              (data (mapcar (lambda (c) (cons c (org-persist-write:generic c 
collection)))
+                            (plist-get collection :container))))
+          (puthash file data org-persist--write-cache)
+          (org-persist--write-elisp-file file data)
+          (or ignore-return (org-persist-read container associated)))))))
 
 (defun org-persist-write-all (&optional associated)
   "Save all the persistent data.
 When ASSOCIATED is non-nil, only save the matching data."
   (unless org-persist--index (org-persist--load-index))
   (setq associated (org-persist--normalize-associated associated))
-  (let (all-containers)
-    (dolist (collection org-persist--index)
-      (if associated
-          (when collection
-            (cl-pushnew (plist-get collection :container) all-containers :test 
#'equal))
-        (condition-case err
-            (org-persist-write (plist-get collection :container) (plist-get 
collection :associated) t)
-          (error
-           (message "%s. Deleting bad index entry." err)
-           (org-persist--remove-from-index collection)
-           nil))))
-    (dolist (container all-containers)
-      (let ((collection (org-persist--find-index `(:container ,container 
:associated ,associated))))
-        (when collection
+  (unless
+      (and (equal 1 (length org-persist--index))
+           ;; The single collection only contains a single container
+           ;; in the container list.
+           (equal 1 (length (plist-get (car org-persist--index) :container)))
+           ;; The container is an `index' container.
+           (eq 'index (caar (plist-get (car org-persist--index) :container)))
+           ;; No `org-persist-directory' exists yet.
+           (not (file-exists-p org-persist-directory)))
+    (let (all-containers)
+      (dolist (collection org-persist--index)
+        (if associated
+            (when collection
+              (cl-pushnew (plist-get collection :container) all-containers 
:test #'equal))
           (condition-case err
-              (org-persist-write container associated t)
+              (org-persist-write (plist-get collection :container) (plist-get 
collection :associated) t)
             (error
              (message "%s. Deleting bad index entry." err)
              (org-persist--remove-from-index collection)
-             nil)))))))
+             nil))))
+      (dolist (container all-containers)
+        (let ((collection (org-persist--find-index `(:container ,container 
:associated ,associated))))
+          (when collection
+            (condition-case err
+                (org-persist-write container associated t)
+              (error
+               (message "%s. Deleting bad index entry." err)
+               (org-persist--remove-from-index collection)
+               nil))))))))
 
 (defun org-persist-write-all-buffer ()
   "Call `org-persist-write-all' in current buffer.
@@ -924,45 +935,40 @@ Do nothing in an indirect buffer."
 (defun org-persist-gc ()
   "Remove expired or unregistered containers.
 Also, remove containers associated with non-existing files."
-  (unless (and org-persist-disable-when-emacs-Q
-               ;; FIXME: This is relying on undocumented fact that
-               ;; Emacs sets `user-init-file' to nil when loaded with
-               ;; "-Q" argument.
-               (not user-init-file))
-    (let (new-index (remote-files-num 0))
-      (dolist (collection org-persist--index)
-        (let* ((file (plist-get (plist-get collection :associated) :file))
-               (file-remote (when file (file-remote-p file)))
-               (persist-file (when (plist-get collection :persist-file)
-                               (org-file-name-concat
-                                org-persist-directory
-                                (plist-get collection :persist-file))))
-               (expired? (org-persist--gc-expired-p
-                          (plist-get collection :expiry) collection)))
-          (when persist-file
-            (when file
-              (when file-remote (cl-incf remote-files-num))
-              (unless (if (not file-remote)
-                          (file-exists-p file)
-                        (pcase org-persist-remote-files
-                          ('t t)
-                          ('check-existence
-                           (file-exists-p file))
-                          ((pred numberp)
-                           (<= org-persist-remote-files remote-files-num))
-                          (_ nil)))
-                (setq expired? t)))
-            (if expired?
-                (org-persist--gc-persist-file persist-file)
-              (push collection new-index)))))
-      (setq org-persist--index (nreverse new-index)))))
+  (let (new-index (remote-files-num 0))
+    (dolist (collection org-persist--index)
+      (let* ((file (plist-get (plist-get collection :associated) :file))
+             (file-remote (when file (file-remote-p file)))
+             (persist-file (when (plist-get collection :persist-file)
+                             (org-file-name-concat
+                              org-persist-directory
+                              (plist-get collection :persist-file))))
+             (expired? (org-persist--gc-expired-p
+                        (plist-get collection :expiry) collection)))
+        (when persist-file
+          (when file
+            (when file-remote (cl-incf remote-files-num))
+            (unless (if (not file-remote)
+                        (file-exists-p file)
+                      (pcase org-persist-remote-files
+                        ('t t)
+                        ('check-existence
+                         (file-exists-p file))
+                        ((pred numberp)
+                         (<= org-persist-remote-files remote-files-num))
+                        (_ nil)))
+              (setq expired? t)))
+          (if expired?
+              (org-persist--gc-persist-file persist-file)
+            (push collection new-index)))))
+    (setq org-persist--index (nreverse new-index))))
 
 ;; Automatically write the data, but only when we have write access.
 (let ((dir (directory-file-name
             (file-name-as-directory org-persist-directory))))
   (while (and (not (file-exists-p dir))
               (not (equal dir (setq dir (directory-file-name
-                                       (file-name-directory dir)))))))
+                                         (file-name-directory dir)))))))
   (if (not (file-writable-p dir))
       (message "Missing write access rights to org-persist-directory: %S"
                org-persist-directory)
@@ -971,6 +977,15 @@ Also, remove containers associated with non-existing 
files."
     ;; So we are adding the hook after `org-persist-write-all'.
     (add-hook 'kill-emacs-hook #'org-persist-gc)))
 
+;; Point to temp directory when `org-persist--disable-when-emacs-Q' is set.
+(if (and org-persist--disable-when-emacs-Q
+         ;; FIXME: This is relying on undocumented fact that
+         ;; Emacs sets `user-init-file' to nil when loaded with
+         ;; "-Q" argument.
+         (not user-init-file))
+    (setq org-persist-directory
+          (make-temp-file "org-persist-" 'dir)))
+
 (add-hook 'after-init-hook #'org-persist-load-all)
 
 (provide 'org-persist)
diff --git a/lisp/org/org-table.el b/lisp/org/org-table.el
index 8e0e8e6cf8..fa9a0319be 100644
--- a/lisp/org/org-table.el
+++ b/lisp/org/org-table.el
@@ -41,6 +41,7 @@
 (require 'org-macs)
 (require 'org-compat)
 (require 'org-keys)
+(require 'org-fold-core)
 
 (declare-function calc-eval "calc" (str &optional separator &rest args))
 (declare-function face-remap-remove-relative "face-remap" (cookie))
@@ -4448,6 +4449,13 @@ FIELD is a string.  WIDTH is a number.  ALIGN is either 
\"c\",
 (defun org-table-justify-field-maybe (&optional new)
   "Justify the current field, text to left, number to right.
 Optional argument NEW may specify text to replace the current field content."
+  ;; FIXME: Prevent newlines inside field.  They are currently not
+  ;; supported.
+  (when (and (stringp new) (string-match-p "\n" new))
+    (message "Removing newlines from formula result: %S" new)
+    (setq new (replace-regexp-in-string
+               "\n" " "
+               (replace-regexp-in-string "\\(^\n+\\)\\|\\(\n+$\\)" "" new))))
   (cond
    ((and (not new) org-table-may-need-update)) ; Realignment will happen anyway
    ((org-at-table-hline-p))
@@ -5721,31 +5729,32 @@ This may be either a string or a function of two 
arguments:
     ;; Initialize communication channel in INFO.
     (with-temp-buffer
       (let ((org-inhibit-startup t)) (org-mode))
-      (let ((standard-output (current-buffer))
-           (org-element-use-cache nil))
-       (dolist (e table)
-         (cond ((eq e 'hline) (princ "|--\n"))
-               ((consp e)
-                (princ "| ") (dolist (c e) (princ c) (princ " |"))
-                (princ "\n")))))
-      (org-element-cache-reset)
-      ;; Add back-end specific filters, but not user-defined ones.  In
-      ;; particular, make sure to call parse-tree filters on the
-      ;; table.
-      (setq info
-           (let ((org-export-filters-alist nil))
-             (org-export-install-filters
-              (org-combine-plists
-               (org-export-get-environment backend nil params)
-               `(:back-end ,(org-export-get-backend backend))))))
-      (setq data
-           (org-export-filter-apply-functions
-            (plist-get info :filter-parse-tree)
-            (org-element-map (org-element-parse-buffer) 'table
-              #'identity nil t)
-            info)))
-    (when (and backend (symbolp backend) (not (org-export-get-backend 
backend)))
-      (user-error "Unknown :backend value"))
+      (org-fold-core-ignore-modifications
+        (let ((standard-output (current-buffer))
+             (org-element-use-cache nil))
+         (dolist (e table)
+           (cond ((eq e 'hline) (princ "|--\n"))
+                 ((consp e)
+                  (princ "| ") (dolist (c e) (princ c) (princ " |"))
+                  (princ "\n")))))
+        (org-element-cache-reset)
+        ;; Add back-end specific filters, but not user-defined ones.  In
+        ;; particular, make sure to call parse-tree filters on the
+        ;; table.
+        (setq info
+             (let ((org-export-filters-alist nil))
+               (org-export-install-filters
+                (org-combine-plists
+                 (org-export-get-environment backend nil params)
+                 `(:back-end ,(org-export-get-backend backend))))))
+        (setq data
+             (org-export-filter-apply-functions
+              (plist-get info :filter-parse-tree)
+              (org-element-map (org-element-parse-buffer) 'table
+                #'identity nil t)
+              info))
+        (when (and backend (symbolp backend) (not (org-export-get-backend 
backend)))
+          (user-error "Unknown :backend value"))))
     (when (or (not backend) (plist-get info :raw)) (require 'ox-org))
     ;; Handle :skip parameter.
     (let ((skip (plist-get info :skip)))
diff --git a/lisp/org/org-version.el b/lisp/org/org-version.el
index e933969040..8de0d1a4a9 100644
--- a/lisp/org/org-version.el
+++ b/lisp/org/org-version.el
@@ -11,7 +11,7 @@ Inserted by installing Org mode or when a release is made."
 (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-3-ga4d38e"))
+   (let ((org-git-version "release_9.6-49-g47d129"))
      org-git-version))
 
 (provide 'org-version)
diff --git a/lisp/org/org.el b/lisp/org/org.el
index ab6212dacc..6aa2a16219 100644
--- a/lisp/org/org.el
+++ b/lisp/org/org.el
@@ -102,6 +102,7 @@
 
 (require 'org-cycle)
 (defvaralias 'org-hide-block-startup 'org-cycle-hide-block-startup)
+(defvaralias 'org-hide-drawer-startup 'org-cycle-hide-drawer-startup)
 (defvaralias 'org-pre-cycle-hook 'org-cycle-pre-hook)
 (defvaralias 'org-tab-first-hook 'org-cycle-tab-first-hook)
 (defalias 'org-global-cycle #'org-cycle-global)
@@ -4596,8 +4597,8 @@ is available.  This option applies only if FILE is a URL."
 This checks every pattern in `org-safe-remote-resources', and
 returns non-nil if any of them match."
   (let ((uri-patterns org-safe-remote-resources)
-        (file-uri (and buffer-file-name
-                       (concat "file://" (file-truename buffer-file-name))))
+        (file-uri (and (buffer-file-name (buffer-base-buffer))
+                       (concat "file://" (file-truename (buffer-file-name 
(buffer-base-buffer))))))
         match-p)
     (while (and (not match-p) uri-patterns)
       (setq match-p (or (string-match-p (car uri-patterns) uri)
@@ -4608,7 +4609,8 @@ returns non-nil if any of them match."
 (defun org--confirm-resource-safe (uri)
   "Ask the user if URI should be considered safe, returning non-nil if so."
   (unless noninteractive
-    (let ((current-file (and buffer-file-name (file-truename 
buffer-file-name)))
+    (let ((current-file (and (buffer-file-name (buffer-base-buffer))
+                             (file-truename (buffer-file-name 
(buffer-base-buffer)))))
           (domain (and (string-match
                         (rx (seq "http" (? "s") "://")
                             (optional (+ (not (any "@/\n"))) "@")
@@ -11380,7 +11382,7 @@ See also `org-scan-tags'."
                             (pv (match-string 7 term))
                             (regexp (eq (string-to-char pv) ?{))
                             (strp (eq (string-to-char pv) ?\"))
-                            (timep (string-match-p "^\"[[<][0-9]+.*[]>]\"$" 
pv))
+                            (timep (string-match-p 
"^\"[[<]\\(?:[0-9]+\\|now\\|today\\|tomorrow\\|[+-][0-9]+[dmwy]\\).*[]>]\"$" 
pv))
                             (po (org-op-to-function (match-string 6 term)
                                                     (if timep 'time strp))))
                        (setq pv (if (or regexp strp) (substring pv 1 -1) pv))
@@ -16322,6 +16324,10 @@ buffer boundaries with possible narrowing."
                                          (org-element-property :end link))
                                         (skip-chars-backward " \t")
                                         (point)))))
+                              ;; FIXME: See bug#59902.  We cannot rely
+                              ;; on Emacs to update image if the file
+                              ;; has changed.
+                              (image-flush image)
                              (overlay-put ov 'display image)
                              (overlay-put ov 'face 'default)
                              (overlay-put ov 'org-image-overlay t)
@@ -16395,6 +16401,10 @@ buffer boundaries with possible narrowing."
   "Remove inline-display overlay if a corresponding region is modified."
   (when (and ov after)
     (delete ov org-inline-image-overlays)
+    ;; Clear image from cache to avoid image not updating upon
+    ;; changing on disk.  See Emacs bug#59902.
+    (when (overlay-get ov 'org-image-overlay)
+      (image-flush (overlay-get ov 'display)))
     (delete-overlay ov)))
 
 (defun org-remove-inline-images (&optional beg end)
diff --git a/lisp/org/ox-md.el b/lisp/org/ox-md.el
index 01e0aa0491..dcd95e9871 100644
--- a/lisp/org/ox-md.el
+++ b/lisp/org/ox-md.el
@@ -87,7 +87,8 @@ included into another document or application that reserves 
top-level
 headings for its own use."
   :group 'org-export-md
   :package-version '(Org . "9.6")
-  :type 'natnum)
+  ;; Avoid `natnum' because that's not available until Emacs 28.1.
+  :type 'integer)
 
 
 
diff --git a/lisp/org/ox.el b/lisp/org/ox.el
index 5c0a8f2424..737703f11d 100644
--- a/lisp/org/ox.el
+++ b/lisp/org/ox.el
@@ -2559,7 +2559,7 @@ variable and do not do anything that might alter it (like 
calling a
 major mode) to prevent data corruption.  Also, do note that Emacs may
 jump into the created buffer if the original file buffer is closed and
 then re-opened.  Making edits in the buffer copy may also trigger
-Emacs save dialogue.  Prefer using `org-export-with-buffer-copy' macro
+Emacs save dialog.  Prefer using `org-export-with-buffer-copy' macro
 when possible.
 
 When optional key `:to-buffer' is non-nil, copy into BUFFER.
@@ -3036,6 +3036,11 @@ Return code as a string."
               (org-narrow-to-subtree)
               (goto-char (point-min))
               (org-end-of-meta-data)
+               ;; Make the region include top heading in the subtree.
+               ;; This way, we will be able to retrieve its export
+               ;; options when calling
+               ;; `org-export--get-subtree-options'.
+               (backward-char)
               (narrow-to-region (point) (point-max))))
         ;; Initialize communication channel with original buffer
         ;; attributes, unavailable in its copy.
@@ -4607,12 +4612,17 @@ If LINK refers to a remote resource, modify it to point 
to a local
 downloaded copy.  Otherwise, return unchanged LINK."
   (when (org-export-link-remote-p link)
     (let* ((local-path (org-export-link--remote-local-copy link)))
-      (setcdr link
-              (thread-first (cadr link)
-                            (plist-put :type "file")
-                            (plist-put :path local-path)
-                            (plist-put :raw-link (concat "file:" local-path))
-                            list))))
+      (if local-path
+          (setcdr link
+                  (thread-first (cadr link)
+                                (plist-put :type "file")
+                                (plist-put :path local-path)
+                                (plist-put :raw-link (concat "file:" 
local-path))
+                                list))
+        (display-warning
+         '(org export)
+         (format "unable to obtain local copy of %s"
+                 (org-element-property :raw-link link))))))
   link)
 
 ;;;; For References
@@ -4748,23 +4758,27 @@ objects of the same type."
      (let ((counter 0))
        ;; Increment counter until ELEMENT is found again.
        (org-element-map (plist-get info :parse-tree)
-          (or types (org-element-type element))
+          (or (and types (cons (org-element-type element) types))
+               (org-element-type element))
         (lambda (el)
            (let ((cached (org-element-property :org-export--counter el)))
             (cond
              ((eq element el) (1+ counter))
               ;; Use cached result.
-              ((and cached (equal predicate (car cached)))
-               (cdr cached))
+              ((and cached
+                    (equal predicate (car cached))
+                    (equal types (cadr cached)))
+               (setq counter (nth 2 cached))
+               nil)
              ((not predicate)
                (cl-incf counter)
                (org-element-put-property
-                el :org-export--counter (cons predicate counter))
+                el :org-export--counter (list predicate types counter))
                nil)
              ((funcall predicate el info)
                (cl-incf counter)
                (org-element-put-property
-                el :org-export--counter (cons predicate counter))
+                el :org-export--counter (list predicate types counter))
                nil))))
         info 'first-match)))))
 
diff --git a/lisp/outline.el b/lisp/outline.el
index 2c3f9798ec..53bfc4d556 100644
--- a/lisp/outline.el
+++ b/lisp/outline.el
@@ -1817,7 +1817,7 @@ With a prefix argument, show headings up to that LEVEL."
         (unless o
           (when (eq outline-minor-mode-use-buttons 'insert)
             (let ((inhibit-read-only t))
-              (insert "  ")
+              (insert (apply #'propertize "  " (text-properties-at (point))))
               (beginning-of-line)))
           (setq o (make-overlay (point) (1+ (point))))
           (overlay-put o 'outline-button t)
diff --git a/lisp/pcomplete.el b/lisp/pcomplete.el
index 8be026b5a8..4e3a88bbda 100644
--- a/lisp/pcomplete.el
+++ b/lisp/pcomplete.el
@@ -1456,7 +1456,7 @@ COMMAND and ARGS as arguments."
                            (pcomplete-match-string 1 0)))
           ((string-prefix-p "-" (pcomplete-arg 0))
            (pcomplete-here (apply #'pcomplete-from-help command args)))
-          (t (pcomplete-here (pcomplete-entries))))))
+          (t (pcomplete-here* (pcomplete-entries))))))
 
 (provide 'pcomplete)
 
diff --git a/lisp/proced.el b/lisp/proced.el
index c7419288ed..c09ee18a8b 100644
--- a/lisp/proced.el
+++ b/lisp/proced.el
@@ -656,6 +656,14 @@ Important: the match ends just after the marker.")
   )
 (put 'proced-mark :advertised-binding "m")
 
+(defvar-local proced-refinements nil
+  "Information about the current buffer refinements.
+
+It should be a list of elements of the form (REFINER PID KEY GRAMMAR), where
+REFINER and GRAMMAR are as described in `proced-grammar-alist', PID is the
+process ID of the process used to create the refinement, and KEY the attribute
+of the process.  A value of nil indicates that there are no active 
refinements.")
+
 (easy-menu-define proced-menu proced-mode-map
   "Proced Menu."
   `("Proced"
@@ -1337,20 +1345,7 @@ a certain refinement, consider defining a new filter in 
`proced-filter-alist'."
         (let* ((grammar (assq key proced-grammar-alist))
                (refiner (nth 7 grammar)))
           (when refiner
-            (cond ((functionp (car refiner))
-                   (setq proced-process-alist (funcall (car refiner) pid)))
-                  ((consp refiner)
-                   (let ((predicate (nth 4 grammar))
-                         (ref (cdr (assq key (cdr (assq pid 
proced-process-alist)))))
-                         val new-alist)
-                     (dolist (process proced-process-alist)
-                       (setq val (funcall predicate (cdr (assq key (cdr 
process))) ref))
-                       (if (cond ((not val) (nth 2 refiner))
-                                 ((eq val 'equal) (nth 1 refiner))
-                                 (val (car refiner)))
-                           (push process new-alist)))
-                     (setq proced-process-alist new-alist))))
-            ;; Do not revert listing.
+            (add-to-list 'proced-refinements (list refiner pid key grammar) t)
             (proced-update)))
       (message "No refiner defined here."))))
 
@@ -1859,10 +1854,29 @@ After updating a displayed Proced buffer run the normal 
hook
                        "Updating process display...")))
   (if revert ;; evaluate all processes
       (setq proced-process-alist (proced-process-attributes)))
-  ;; filtering and sorting
+  ;; filtering
+  (setq proced-process-alist (proced-filter proced-process-alist 
proced-filter))
+  ;; refinements
+  (pcase-dolist (`(,refiner ,pid ,key ,grammar) proced-refinements)
+    ;; It's possible the process has exited since the refinement was made
+    (when (assq pid proced-process-alist)
+      (cond ((functionp (car refiner))
+             (setq proced-process-alist (funcall (car refiner) pid)))
+            ((consp refiner)
+             (let ((predicate (nth 4 grammar))
+                   (ref (cdr (assq key (cdr (assq pid proced-process-alist)))))
+                   val new-alist)
+               (dolist (process proced-process-alist)
+                 (setq val (funcall predicate (cdr (assq key (cdr process))) 
ref))
+                 (when (cond ((not val) (nth 2 refiner))
+                             ((eq val 'equal) (nth 1 refiner))
+                             (val (car refiner)))
+                   (push process new-alist)))
+               (setq proced-process-alist new-alist))))))
+
+  ;; sorting
   (setq proced-process-alist
-        (proced-sort (proced-filter proced-process-alist proced-filter)
-                     proced-sort proced-descend))
+        (proced-sort proced-process-alist proced-sort proced-descend))
 
   ;; display as process tree?
   (setq proced-process-alist
@@ -1976,7 +1990,9 @@ After updating a displayed Proced buffer run the normal 
hook
 
 (defun proced-revert (&rest _args)
   "Reevaluate the process listing based on the currently running processes.
-Preserves point and marks."
+Preserves point and marks, but not refinements (see `proced-refine' for
+information on refinements)."
+  (setq proced-refinements nil)
   (proced-update t))
 
 (defun proced-marked-processes ()
diff --git a/lisp/progmodes/bat-mode.el b/lisp/progmodes/bat-mode.el
index 6bac297a29..5e833047af 100644
--- a/lisp/progmodes/bat-mode.el
+++ b/lisp/progmodes/bat-mode.el
@@ -44,7 +44,7 @@
 ;; Separate package `dos-indent' (Matthew Fidler) provides rudimentary
 ;; indentation, see https://www.emacswiki.org/emacs/dos-indent.el.
 ;;
-;; Acknowledgements:
+;; Acknowledgments:
 ;;
 ;; Inspired by `batch-mode' (Agnar Renolen) and `cmd-mode' (Tadamegu Furukawa).
 
diff --git a/lisp/progmodes/c-ts-mode.el b/lisp/progmodes/c-ts-mode.el
index 1bd093cfa2..cf941236f8 100644
--- a/lisp/progmodes/c-ts-mode.el
+++ b/lisp/progmodes/c-ts-mode.el
@@ -9,19 +9,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
@@ -79,9 +78,19 @@ follows the form of `treesit-simple-indent-rules'."
     (modify-syntax-entry ?\240 "."   table)
     (modify-syntax-entry ?/  ". 124b" table)
     (modify-syntax-entry ?*  ". 23"   table)
+    (modify-syntax-entry ?\n "> b"  table)
+    (modify-syntax-entry ?\^m "> b" table)
     table)
   "Syntax table for `c-ts-mode'.")
 
+(defvar c++-ts-mode--syntax-table
+  (let ((table (make-syntax-table c-ts-mode--syntax-table)))
+    ;; Template delimiters.
+    (modify-syntax-entry ?<  "("     table)
+    (modify-syntax-entry ?>  ")"     table)
+    table)
+  "Syntax table for `c++-ts-mode'.")
+
 (defun c-ts-mode--indent-styles (mode)
   "Indent rules supported by `c-ts-mode'.
 MODE is either `c' or `cpp'."
@@ -94,7 +103,6 @@ MODE is either `c' or `cpp'."
            ((node-is "case") parent-bol 0)
            ((node-is "preproc_arg") no-indent)
            ((and (parent-is "comment") comment-end) comment-start -1)
-           ((parent-is "comment") comment-start-skip 0)
            ((node-is "labeled_statement") parent-bol 0)
            ((parent-is "labeled_statement") parent-bol c-ts-mode-indent-offset)
            ((match "preproc_ifdef" "compound_statement") point-min 0)
@@ -119,6 +127,8 @@ MODE is either `c' or `cpp'."
            ((query "(call_expression arguments: (_) @indent)") parent 
c-ts-mode-indent-offset)
            ((parent-is "call_expression") parent 0)
            ((parent-is "enumerator_list") parent-bol c-ts-mode-indent-offset)
+           ,@(when (eq mode 'cpp)
+               '(((node-is "access_specifier") parent-bol 0)))
            ((parent-is "field_declaration_list") parent-bol 
c-ts-mode-indent-offset)
            ((parent-is "initializer_list") parent-bol c-ts-mode-indent-offset)
            ((parent-is "if_statement") parent-bol c-ts-mode-indent-offset)
@@ -169,9 +179,9 @@ MODE is either `c' or `cpp'."
          '("break" "case" "const" "continue"
            "default" "do" "else" "enum"
            "extern" "for" "goto" "if" "inline"
-           "long" "register" "return" "short"
-           "signed" "sizeof" "static" "struct"
-           "switch" "typedef" "union" "unsigned"
+           "register" "return"
+           "sizeof" "static" "struct"
+           "switch" "typedef" "union"
            "volatile" "while")))
     (if (eq mode 'cpp)
         (append c-keywords
@@ -188,6 +198,10 @@ MODE is either `c' or `cpp'."
                   "xor" "xor_eq"))
       (append '("auto") c-keywords))))
 
+(defvar c-ts-mode--type-keywords
+  '("long" "short" "signed" "unsigned")
+  "Keywords that should be considered as part of a type.")
+
 (defvar c-ts-mode--operators
   '("=" "-" "*" "/" "+" "%" "~" "|" "&" "^" "<<" ">>" "->"
     "." "<" "<=" ">=" ">" "==" "!=" "!" "&&" "||" "-="
@@ -229,13 +243,14 @@ MODE is either `c' or `cpp'."
      (false) @font-lock-constant-face
      (null) @font-lock-constant-face
      ,@(when (eq mode 'cpp)
-         '((this) @font-lock-constant-face)))
+         '((nullptr) @font-lock-constant-face)))
 
    :language mode
    :feature 'keyword
    `([,@(c-ts-mode--keywords mode)] @font-lock-keyword-face
      ,@(when (eq mode 'cpp)
-         '((auto) @font-lock-keyword-face)))
+         '((auto) @font-lock-keyword-face
+           (this) @font-lock-keyword-face)))
 
    :language mode
    :feature 'operator
@@ -245,7 +260,9 @@ MODE is either `c' or `cpp'."
    :language mode
    :feature 'string
    `((string_literal) @font-lock-string-face
-     (system_lib_string) @font-lock-string-face)
+     (system_lib_string) @font-lock-string-face
+     ,@(when (eq mode 'cpp)
+         '((raw_string_literal) @font-lock-string-face)))
 
    :language mode
    :feature 'literal
@@ -263,7 +280,8 @@ MODE is either `c' or `cpp'."
            (qualified_identifier
             scope: (namespace_identifier) @font-lock-type-face)
 
-           (operator_cast) type: (type_identifier) @font-lock-type-face)))
+           (operator_cast) type: (type_identifier) @font-lock-type-face))
+     [,@c-ts-mode--type-keywords] @font-lock-type-face)
 
    :language mode
    :feature 'definition
@@ -314,7 +332,7 @@ MODE is either `c' or `cpp'."
 
    :language mode
    :feature 'error
-   '((ERROR) @c-ts-fontify-error)
+   '((ERROR) @c-ts-mode--fontify-error)
 
    :feature 'escape-sequence
    :language mode
@@ -367,8 +385,8 @@ For NODE, OVERRIDE, START, END, and ARGS, see
       override start end))))
 
 (defun c-ts-mode--fontify-variable (node override start end &rest _)
-  "Fontify an identifier node.
-Fontify it if NODE is not a function identifier.  For NODE,
+  "Fontify an identifier node if it is a variable.
+Don't fontify if it is a function identifier.  For NODE,
 OVERRIDE, START, END, and ARGS, see `treesit-font-lock-rules'."
   (when (not (equal (treesit-node-type
                      (treesit-node-parent node))
@@ -416,7 +434,7 @@ This function corrects the fontification on the colon in
            (treesit-node-start arg) (treesit-node-end arg)
            'default override start end))))))
 
-(defun c-ts-fontify-error (node override start end &rest _)
+(defun c-ts-mode--fontify-error (node override start end &rest _)
   "Fontify the error nodes.
 For NODE, OVERRIDE, START, and END, see
 `treesit-font-lock-rules'."
@@ -512,18 +530,63 @@ the subtrees."
       (if (looking-at "\\s<\\|\n")
          (forward-line 1)))))
 
+(defun c-ts-mode--defun-valid-p (node)
+  (if (string-match-p
+       (rx (or "struct_specifier"
+               "enum_specifier"
+               "union_specifier"))
+       (treesit-node-type node))
+      (null
+       (treesit-node-top-level
+        node (rx (or "function_definition"
+                     "type_definition"))))
+    t))
+
+(defun c-ts-mode--defun-skipper ()
+  "Custom defun skipper for `c-ts-mode' and friends.
+Structs in C ends with a semicolon, but the semicolon is not
+considered part of the struct node, so point would stop before
+the semicolon.  This function skips the semicolon."
+  (when (looking-at (rx (* (or " " "\t")) ";"))
+    (goto-char (match-end 0)))
+  (treesit-default-defun-skipper))
+
+(defun c-ts-mode-indent-defun ()
+  "Indent the current top-level declaration syntactically.
+
+`treesit-defun-type-regexp' defines what constructs to indent."
+  (interactive "*")
+  (let ((orig-point (point-marker)))
+    ;; If `treesit-beginning-of-defun' returns nil, we are not in a
+    ;; defun, so don't indent anything.
+    (when (treesit-beginning-of-defun)
+      (let ((start (point)))
+        (treesit-end-of-defun)
+        (indent-region start (point))))
+    (goto-char orig-point)))
+
+(defvar-keymap c-ts-mode-map
+  :doc "Keymap for the C language with tree-sitter"
+  :parent prog-mode-map
+  "C-c C-q" #'c-ts-mode-indent-defun)
+
 ;;;###autoload
 (define-derived-mode c-ts-base-mode prog-mode "C"
-  "Major mode for editing C, powered by tree-sitter."
+  "Major mode for editing C, powered by tree-sitter.
+
+\\{c-ts-mode-map}"
   :syntax-table c-ts-mode--syntax-table
 
   ;; Navigation.
   (setq-local treesit-defun-type-regexp
-              (regexp-opt '("function_definition"
-                            "type_definition"
-                            "struct_specifier"
-                            "enum_specifier"
-                            "union_specifier")))
+              (cons (regexp-opt '("function_definition"
+                                  "type_definition"
+                                  "struct_specifier"
+                                  "enum_specifier"
+                                  "union_specifier"
+                                  "class_specifier"))
+                    #'c-ts-mode--defun-valid-p))
+  (setq-local treesit-defun-skipper #'c-ts-mode--defun-skipper)
 
   ;; Nodes like struct/enum/union_specifier can appear in
   ;; function_definitions, so we need to find the top-level node.
@@ -584,6 +647,7 @@ the subtrees."
 (define-derived-mode c++-ts-mode c-ts-base-mode "C++"
   "Major mode for editing C++, powered by tree-sitter."
   :group 'c++
+  :syntax-table c++-ts-mode--syntax-table
 
   (unless (treesit-ready-p 'cpp)
     (error "Tree-sitter for C++ isn't available"))
@@ -599,6 +663,10 @@ the subtrees."
                   (group (or (syntax comment-end)
                              (seq (+ "*") "/")))))
 
+  (setq-local treesit-text-type-regexp
+              (regexp-opt '("comment"
+                            "raw_string_literal")))
+
   (treesit-parser-create 'cpp)
 
   (setq-local treesit-simple-indent-rules
diff --git a/lisp/progmodes/cc-defs.el b/lisp/progmodes/cc-defs.el
index b13f6a5914..dd6d33009d 100644
--- a/lisp/progmodes/cc-defs.el
+++ b/lisp/progmodes/cc-defs.el
@@ -1826,7 +1826,7 @@ with value CHAR in the region [FROM to)."
     '(or (looking-at
          "\\([;#]\\|\\'\\|\\s(\\|\\s)\\|\\s\"\\|\\s\\\\|\\s$\\|\\s<\\|\\s>\\)"
          (let ((prop (c-get-char-property (point) 'syntax-table)))
-           (eq prop '(14)))))))                ; '(14) is generic comment 
delimiter.
+           (equal prop '(14))))))) ; '(14) is generic comment delimiter.
 
 
 (defsubst c-intersect-lists (list alist)
diff --git a/lisp/progmodes/cmake-ts-mode.el b/lisp/progmodes/cmake-ts-mode.el
new file mode 100644
index 0000000000..fc25d2ba5f
--- /dev/null
+++ b/lisp/progmodes/cmake-ts-mode.el
@@ -0,0 +1,234 @@
+;;; cmake-ts-mode.el --- tree-sitter support for CMake  -*- lexical-binding: 
t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author     : Randy Taylor <dev@rjt.dev>
+;; Maintainer : Randy Taylor <dev@rjt.dev>
+;; Created    : December 2022
+;; Keywords   : cmake languages tree-sitter
+
+;; 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:
+;;
+
+;;; Code:
+
+(require 'treesit)
+(eval-when-compile (require 'rx))
+
+(declare-function treesit-parser-create "treesit.c")
+(declare-function treesit-induce-sparse-tree "treesit.c")
+(declare-function treesit-node-child "treesit.c")
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
+
+(defcustom cmake-ts-mode-indent-offset 2
+  "Number of spaces for each indentation step in `cmake-ts-mode'."
+  :version "29.1"
+  :type 'integer
+  :safe 'integerp
+  :group 'cmake)
+
+(defvar cmake-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?#  "<" table)
+    (modify-syntax-entry ?\n ">" table)
+    (modify-syntax-entry ?$  "'" table)
+    table)
+  "Syntax table for `cmake-ts-mode'.")
+
+(defvar cmake-ts-mode--indent-rules
+  `((cmake
+     ((node-is ")") parent-bol 0)
+     ((node-is "else_command") parent-bol 0)
+     ((node-is "elseif_command") parent-bol 0)
+     ((node-is "endforeach_command") parent-bol 0)
+     ((node-is "endfunction_command") parent-bol 0)
+     ((node-is "endif_command") parent-bol 0)
+     ((parent-is "foreach_loop") parent-bol cmake-ts-mode-indent-offset)
+     ((parent-is "function_def") parent-bol cmake-ts-mode-indent-offset)
+     ((parent-is "if_condition") parent-bol cmake-ts-mode-indent-offset)
+     ((parent-is "normal_command") parent-bol cmake-ts-mode-indent-offset)))
+  "Tree-sitter indent rules for `cmake-ts-mode'.")
+
+(defvar cmake-ts-mode--constants
+  '("1" "ON" "TRUE" "YES" "Y" "0" "OFF" "FALSE" "NO" "N" "IGNORE"
+    "NOTFOUND")
+  "CMake constants for tree-sitter font-locking.")
+
+(defvar cmake-ts-mode--keywords
+  '((else) (elseif) (endforeach) (endfunction) (endif) (endmacro)
+    (endwhile) (foreach) (function) (if) (macro) (while))
+  "CMake keywords for tree-sitter font-locking.")
+
+(defvar cmake-ts-mode--foreach-options
+  '("IN" "ITEMS" "LISTS" "RANGE" "ZIP_LISTS")
+  "CMake foreach options for tree-sitter font-locking.")
+
+(defvar cmake-ts-mode--if-conditions
+  '("AND" "COMMAND" "DEFINED" "EQUAL" "EXISTS" "GREATER"
+    "GREATER_EQUAL" "LESS" "LESS_EQUAL" "MATCHES" "NOT" "OR"
+    "PATH_EQUAL" "STREQUAL" "STRGREATER" "STRGREATER_EQUAL" "STRLESS"
+    "STRLESS_EQUAL" "VERSION_EQUAL" "VERSION_GREATER"
+    "VERSION_GREATER_EQUAL" "VERSION_LESS" "VERSION_LESS_EQUAL")
+  "CMake if conditions for tree-sitter font-locking.")
+
+(defvar cmake-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'cmake
+   :feature 'bracket
+   '((["(" ")"]) @font-lock-bracket-face)
+
+   :language 'cmake
+   :feature 'builtin
+   `(((foreach_command
+       ((argument) @font-lock-constant-face
+        (:match ,(rx-to-string
+                  `(seq bol
+                        (or ,@cmake-ts-mode--foreach-options)
+                        eol))
+                @font-lock-constant-face))))
+     ((if_command
+       ((argument) @font-lock-constant-face
+        (:match ,(rx-to-string
+                  `(seq bol
+                        (or ,@cmake-ts-mode--if-conditions)
+                        eol))
+                @font-lock-constant-face)))))
+
+   :language 'cmake
+   :feature 'comment
+   '([(bracket_comment) (line_comment)] @font-lock-comment-face)
+
+   :language 'cmake
+   :feature 'constant
+   `(((argument) @font-lock-constant-face
+      (:match ,(rx-to-string
+                `(seq bol
+                      (or ,@cmake-ts-mode--constants)
+                      eol))
+              @font-lock-constant-face)))
+
+   :language 'cmake
+   :feature 'function
+   '((normal_command (identifier) @font-lock-function-name-face))
+
+   :language 'cmake
+   :feature 'keyword
+   `([,@cmake-ts-mode--keywords] @font-lock-keyword-face)
+
+   :language 'cmake
+   :feature 'number
+   '(((unquoted_argument) @font-lock-number-face
+      (:match "^[[:digit:]]*\\.?[[:digit:]]*\\.?[[:digit:]]+$" 
@font-lock-number-face)))
+
+   :language 'cmake
+   :feature 'string
+   '([(bracket_argument) (quoted_argument)] @font-lock-string-face)
+
+   :language 'cmake
+   :feature 'escape-sequence
+   :override t
+   '((escape_sequence) @font-lock-escape-face)
+
+   :language 'cmake
+   :feature 'misc-punctuation
+   ;; Don't override strings.
+   :override 'nil
+   '((["$" "{" "}" "<" ">"]) @font-lock-misc-punctuation-face)
+
+   :language 'cmake
+   :feature 'variable
+   :override t
+   '((variable) @font-lock-variable-name-face)
+
+   :language 'cmake
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Tree-sitter font-lock settings for `cmake-ts-mode'.")
+
+(defun cmake-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (func-tree (treesit-induce-sparse-tree
+                     node "function_def" nil 1000))
+         (func-index (cmake-ts-mode--imenu-1 func-tree)))
+    (append
+     (when func-index `(("Function" . ,func-index))))))
+
+(defun cmake-ts-mode--imenu-1 (node)
+  "Helper for `cmake-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (children (cdr node))
+         (subtrees (mapcan #'cmake-ts-mode--imenu-1
+                           children))
+         (name (when ts-node
+                 (pcase (treesit-node-type ts-node)
+                   ("function_def"
+                    (treesit-node-text
+                     (treesit-node-child (treesit-node-child ts-node 0) 2) 
t)))))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((or (null ts-node) (null name)) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist
+             '("\\(?:CMakeLists\\.txt\\|\\.cmake\\)\\'" . cmake-ts-mode))
+
+;;;###autoload
+(define-derived-mode cmake-ts-mode prog-mode "CMake"
+  "Major mode for editing CMake files, powered by tree-sitter."
+  :group 'cmake
+  :syntax-table cmake-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'cmake)
+    (treesit-parser-create 'cmake)
+
+    ;; Comments.
+    (setq-local comment-start "# ")
+    (setq-local comment-end "")
+    (setq-local comment-start-skip (rx "#" (* (syntax whitespace))))
+
+    ;; Imenu.
+    (setq-local imenu-create-index-function #'cmake-ts-mode--imenu)
+    (setq-local which-func-functions nil)
+
+    ;; Indent.
+    (setq-local treesit-simple-indent-rules cmake-ts-mode--indent-rules)
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings cmake-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '((comment)
+                  (keyword string)
+                  (builtin constant escape-sequence function number variable)
+                  (bracket error misc-punctuation)))
+
+    (treesit-major-mode-setup)))
+
+(provide 'cmake-ts-mode)
+
+;;; cmake-ts-mode.el ends here
diff --git a/lisp/progmodes/compile.el b/lisp/progmodes/compile.el
index e8ada9388e..319dc97e69 100644
--- a/lisp/progmodes/compile.el
+++ b/lisp/progmodes/compile.el
@@ -186,6 +186,7 @@ and a string describing how the process finished.")
                      face compilation-info
                      help-echo "Number of informational messages so far")
     "]"))
+(put 'compilation-mode-line-errors 'risky-local-variable t)
 
 ;; If you make any changes to `compilation-error-regexp-alist-alist',
 ;; be sure to run the ERT test in test/lisp/progmodes/compile-tests.el.
diff --git a/lisp/progmodes/csharp-mode.el b/lisp/progmodes/csharp-mode.el
index 054dabfed0..9e8b22c6ab 100644
--- a/lisp/progmodes/csharp-mode.el
+++ b/lisp/progmodes/csharp-mode.el
@@ -11,18 +11,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -505,7 +505,7 @@ compilation and evaluation time conflicts."
 
 (defun csharp--compilation-error-file-resolve ()
   "Resolve an msbuild error to a (filename . dirname) cons cell."
-  ;; http://stackoverflow.com/a/18049590/429091
+  ;; https://stackoverflow.com/a/18049590/429091
   (cons (match-string 1) (file-name-directory (match-string 4))))
 
 (defconst csharp-compilation-re-msbuild-error
@@ -709,8 +709,8 @@ compilation and evaluation time conflicts."
    :language 'c-sharp
    :override t
    :feature 'literal
-   `((integer_literal) @font-lock-constant-face
-     (real_literal) @font-lock-constant-face
+   `((integer_literal) @font-lock-number-face
+     (real_literal) @font-lock-number-face
      (null_literal) @font-lock-constant-face
      (boolean_literal) @font-lock-constant-face)
    :language 'c-sharp
@@ -748,8 +748,11 @@ compilation and evaluation time conflicts."
    :language 'c-sharp
    :feature 'definition
    :override t
-   '((qualified_name (identifier) @font-lock-variable-name-face)
+   '((qualified_name (identifier) @font-lock-type-face)
      (using_directive (identifier) @font-lock-type-face)
+     (using_directive (name_equals
+                       (identifier) @font-lock-type-face
+                       ["="] @default-face))
 
      (enum_declaration (identifier) @font-lock-type-face)
      (enum_member_declaration (identifier) @font-lock-variable-name-face)
@@ -788,7 +791,15 @@ compilation and evaluation time conflicts."
      (invocation_expression
       (identifier) @font-lock-function-name-face)
      (invocation_expression
-      (member_access_expression (identifier) @font-lock-function-name-face))
+      (member_access_expression
+       expression: (identifier) @font-lock-variable-name-face))
+     (invocation_expression
+      function: [(generic_name (identifier)) @font-lock-function-name-face
+                 (generic_name (type_argument_list
+                                ["<"] @font-lock-bracket-face
+                                (identifier) @font-lock-type-face
+                                [">"] @font-lock-bracket-face)
+                               )])
 
      (catch_declaration
       ((identifier) @font-lock-type-face))
@@ -815,7 +826,13 @@ compilation and evaluation time conflicts."
 
    :language 'c-sharp
    :feature 'delimiter
-   '((["," ":" ";"]) @font-lock-delimiter-face)))
+   '((["," ":" ";"]) @font-lock-delimiter-face)
+
+   :language 'c-sharp
+   :feature 'escape-sequence
+   :override t
+   '((escape_sequence) @font-lock-escape-face
+     (ERROR) @font-lock-warning-face)))
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.cs\\'" . csharp-mode))
@@ -890,6 +907,7 @@ Key bindings:
 ;;;###autoload
 (define-derived-mode csharp-ts-mode prog-mode "C#"
   "Major mode for editing C# code."
+  :syntax-table (csharp--make-mode-syntax-table)
 
   (unless (treesit-ready-p 'c-sharp)
     (error "Tree-sitter for C# isn't available"))
@@ -908,6 +926,11 @@ Key bindings:
                   (group (or (syntax comment-end)
                              (seq (+ "*") "/")))))
 
+  (setq-local treesit-text-type-regexp
+              (regexp-opt '("comment"
+                            "verbatim_string-literal"
+                            "interpolated_verbatim_string-text")))
+
   ;; Indent.
   (setq-local treesit-simple-indent-rules csharp-ts-mode--indent-rules)
 
@@ -922,7 +945,7 @@ Key bindings:
   (setq-local treesit-font-lock-settings csharp-ts-mode--font-lock-settings)
   (setq-local treesit-font-lock-feature-list
               '(( comment definition)
-                ( keyword string type)
+                ( keyword string escape-sequence type)
                 ( attribute constant expression literal)
                 ( bracket delimiter)))
 
diff --git a/lisp/progmodes/dockerfile-ts-mode.el 
b/lisp/progmodes/dockerfile-ts-mode.el
new file mode 100644
index 0000000000..40d90cc2df
--- /dev/null
+++ b/lisp/progmodes/dockerfile-ts-mode.el
@@ -0,0 +1,177 @@
+;;; dockerfile-ts-mode.el --- tree-sitter support for Dockerfiles  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author     : Randy Taylor <dev@rjt.dev>
+;; Maintainer : Randy Taylor <dev@rjt.dev>
+;; Created    : December 2022
+;; Keywords   : dockerfile languages tree-sitter
+
+;; 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:
+;;
+
+;;; Code:
+
+(require 'treesit)
+(eval-when-compile (require 'rx))
+
+(declare-function treesit-parser-create "treesit.c")
+(declare-function treesit-induce-sparse-tree "treesit.c")
+(declare-function treesit-node-child "treesit.c")
+(declare-function treesit-node-child-by-field-name "treesit.c")
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
+
+(defvar dockerfile-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?#  "<" table)
+    (modify-syntax-entry ?\n ">" table)
+    table)
+  "Syntax table for `dockerfile-ts-mode'.")
+
+(defvar dockerfile-ts-mode--indent-rules
+  `((dockerfile
+     ((parent-is "copy_instruction") (nth-sibling 1) 0)
+     ((parent-is "env_instruction") (nth-sibling 1) 0)
+     ((parent-is "expose_instruction") (nth-sibling 1) 0)
+     ((parent-is "label_instruction") (nth-sibling 1) 0)
+     ((parent-is "shell_command") first-sibling 0)
+     ((parent-is "string_array") first-sibling 1)))
+  "Tree-sitter indent rules.")
+
+(defvar dockerfile-ts-mode--keywords
+  '("ADD" "ARG" "AS" "CMD" "COPY" "CROSS_BUILD" "ENTRYPOINT" "ENV"
+    "EXPOSE" "FROM" "HEALTHCHECK" "LABEL" "MAINTAINER" "ONBUILD" "RUN"
+    "SHELL" "STOPSIGNAL" "USER" "VOLUME" "WORKDIR")
+  "Dockerfile keywords for tree-sitter font-locking.")
+
+(defvar dockerfile-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'dockerfile
+   :feature 'bracket
+   '((["[" "]"]) @font-lock-bracket-face)
+
+   :language 'dockerfile
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
+
+   :language 'dockerfile
+   :feature 'delimiter
+   '(([","]) @font-lock-delimiter-face)
+
+   :language 'dockerfile
+   :feature 'image-spec
+   '((image_spec) @font-lock-constant-face)
+
+   :language 'dockerfile
+   :feature 'keyword
+   `([,@dockerfile-ts-mode--keywords] @font-lock-keyword-face)
+
+   :language 'dockerfile
+   :feature 'number
+   '((expose_port) @font-lock-number-face)
+
+   :language 'dockerfile
+   :feature 'operator
+   '((["="]) @font-lock-operator-face)
+
+   :language 'dockerfile
+   :feature 'string
+   '((double_quoted_string) @font-lock-string-face)
+
+   :language 'dockerfile
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Tree-sitter font-lock settings.")
+
+(defun dockerfile-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (stage-tree (treesit-induce-sparse-tree
+                      node "from_instruction"
+                      nil 1000)))
+    `(("Stage" . ,(dockerfile-ts-mode--imenu-1 stage-tree)))))
+
+(defun dockerfile-ts-mode--imenu-1 (node)
+  "Helper for `dockerfile-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (children (cdr node))
+         (subtrees (mapcan #'dockerfile-ts-mode--imenu-1
+                           children))
+         (name (when ts-node
+                 (pcase (treesit-node-type ts-node)
+                   ("from_instruction"
+                    (treesit-node-text
+                     (or (treesit-node-child-by-field-name ts-node "as")
+                         (treesit-node-child ts-node 1)) t)))))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((or (null ts-node) (null name)) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist
+             ;; NOTE: We can't use `rx' here, as it breaks bootstrap.
+             '("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'"
+               . dockerfile-ts-mode))
+
+;;;###autoload
+(define-derived-mode dockerfile-ts-mode prog-mode "Dockerfile"
+  "Major mode for editing Dockerfiles, powered by tree-sitter."
+  :group 'dockerfile
+  :syntax-table dockerfile-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'dockerfile)
+    (treesit-parser-create 'dockerfile)
+
+    ;; Comments.
+    (setq-local comment-start "# ")
+    (setq-local comment-end "")
+    (setq-local comment-start-skip (rx "#" (* (syntax whitespace))))
+
+    ;; Imenu.
+    (setq-local imenu-create-index-function
+                #'dockerfile-ts-mode--imenu)
+    (setq-local which-func-functions nil)
+
+    ;; Indent.
+    (setq-local treesit-simple-indent-rules
+                dockerfile-ts-mode--indent-rules)
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings
+                dockerfile-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '((comment)
+                  (keyword string)
+                  (image-spec number)
+                  (bracket delimiter error operator)))
+
+    (treesit-major-mode-setup)))
+
+(provide 'dockerfile-ts-mode)
+
+;;; dockerfile-ts-mode.el ends here
diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el
index c266f6e18a..ce4ca4f3d9 100644
--- a/lisp/progmodes/eglot.el
+++ b/lisp/progmodes/eglot.el
@@ -2,12 +2,12 @@
 
 ;; Copyright (C) 2018-2022 Free Software Foundation, Inc.
 
-;; Version: 1.9
+;; Version: 1.10
 ;; Author: João Távora <joaotavora@gmail.com>
 ;; Maintainer: João Távora <joaotavora@gmail.com>
 ;; URL: https://github.com/joaotavora/eglot
 ;; Keywords: convenience, languages
-;; Package-Requires: ((emacs "26.3") (jsonrpc "1.0.14") (flymake "1.2.1") 
(project "0.3.0") (xref "1.0.1") (eldoc "1.11.0") (seq "2.23"))
+;; Package-Requires: ((emacs "26.3") (jsonrpc "1.0.16") (flymake "1.2.1") 
(project "0.9.3") (xref "1.0.1") (eldoc "1.11.0") (seq "2.23") 
(external-completion "0.1"))
 
 ;; This is a GNU ELPA :core package.  Avoid adding functionality
 ;; that is not available in the version of Emacs recorded above or any
@@ -110,6 +110,7 @@
 (require 'filenotify)
 (require 'ert)
 (require 'array)
+(require 'external-completion)
 
 ;; ElDoc is preloaded in Emacs, so `require'-ing won't guarantee we are
 ;; using the latest version from GNU Elpa when we load eglot.el.  Use an
@@ -181,8 +182,8 @@ chosen (interactively or automatically)."
                       when probe return (cons probe args)
                       finally (funcall err)))))))
 
-(defvar eglot-server-programs `((rust-mode . ,(eglot-alternatives 
'("rust-analyzer" "rls")))
-                                (cmake-mode . ("cmake-language-server"))
+(defvar eglot-server-programs `(((rust-ts-mode rust-mode) . 
,(eglot-alternatives '("rust-analyzer" "rls")))
+                                ((cmake-mode cmake-ts-mode) . 
("cmake-language-server"))
                                 (vimrc-mode . ("vim-language-server" 
"--stdio"))
                                 ((python-mode python-ts-mode)
                                  . ,(eglot-alternatives
@@ -210,7 +211,8 @@ chosen (interactively or automatically)."
                                 (elm-mode . ("elm-language-server"))
                                 (mint-mode . ("mint" "ls"))
                                 (kotlin-mode . ("kotlin-language-server"))
-                                ((go-mode go-dot-mod-mode go-dot-work-mode) . 
("gopls"))
+                                ((go-mode go-dot-mod-mode go-dot-work-mode 
go-ts-mode go-mod-ts-mode)
+                                 . ("gopls"))
                                 ((R-mode ess-r-mode) . ("R" "--slave" "-e"
                                                         
"languageserver::run()"))
                                 ((java-mode java-ts-mode) . ("jdtls"))
@@ -223,7 +225,7 @@ chosen (interactively or automatically)."
                                 ((tex-mode context-mode texinfo-mode 
bibtex-mode)
                                  . ,(eglot-alternatives '("digestif" 
"texlab")))
                                 (erlang-mode . ("erlang_ls" "--transport" 
"stdio"))
-                                (yaml-mode . ("yaml-language-server" 
"--stdio"))
+                                ((yaml-ts-mode yaml-mode) . 
("yaml-language-server" "--stdio"))
                                 (nix-mode . ,(eglot-alternatives '("nil" 
"rnix-lsp")))
                                 (gdscript-mode . ("localhost" 6008))
                                 ((fortran-mode f90-mode) . ("fortls"))
@@ -235,11 +237,13 @@ chosen (interactively or automatically)."
                                  . ,(eglot-alternatives 
'(("vscode-css-language-server" "--stdio")
                                                           
("css-languageserver" "--stdio"))))
                                 (html-mode . ,(eglot-alternatives 
'(("vscode-html-language-server" "--stdio") ("html-languageserver" "--stdio"))))
-                                (dockerfile-mode . ("docker-langserver" 
"--stdio"))
+                                ((dockerfile-mode dockerfile-ts-mode) . 
("docker-langserver" "--stdio"))
                                 ((clojure-mode clojurescript-mode 
clojurec-mode)
                                  . ("clojure-lsp"))
                                 ((csharp-mode csharp-ts-mode)
-                                 . ("omnisharp" "-lsp"))
+                                 . ,(eglot-alternatives
+                                     '(("omnisharp" "-lsp")
+                                       ("csharp-ls"))))
                                 (purescript-mode . 
("purescript-language-server" "--stdio"))
                                 ((perl-mode cperl-mode) . ("perl" 
"-MPerl::LanguageServer" "-e" "Perl::LanguageServer::run"))
                                 (markdown-mode . ("marksman" "server")))
@@ -386,6 +390,11 @@ done by `eglot-reconnect'."
   "String displayed in mode line when Eglot is active."
   :type 'string)
 
+(defcustom eglot-report-progress t
+  "If non-nil, show progress of long running LSP server work"
+  :type 'boolean
+  :version "29.1")
+
 (defvar eglot-withhold-process-id nil
   "If non-nil, Eglot will not send the Emacs process id to the language server.
 This can be useful when using docker to run a language server.")
@@ -470,6 +479,7 @@ This can be useful when using docker to run a language 
server.")
       (TextDocumentEdit (:textDocument :edits) ())
       (TextEdit (:range :newText))
       (VersionedTextDocumentIdentifier (:uri :version) ())
+      (WorkDoneProgress (:kind) (:title :message :percentage :cancellable))
       (WorkspaceEdit () (:changes :documentChanges))
       (WorkspaceSymbol (:name :kind) (:containerName :location :data)))
     "Alist (INTERFACE-NAME . INTERFACE) of known external LSP interfaces.
@@ -492,7 +502,7 @@ Here's what an element of this alist might look like:
       ;; disallow-non-standard-keys
       ;; enforce-required-keys
       ;; enforce-optional-keys
-      )
+      no-unknown-interfaces)
     "How strictly to check LSP interfaces at compile- and run-time.
 
 Value is a list of symbols (if the list is empty, no checks are
@@ -513,7 +523,10 @@ happens at run-time.  At compile-time, a warning is raised 
if a
 destructuring spec doesn't use all optional fields.
 
 If the symbol `disallow-unknown-methods' is present, Eglot warns
-on unknown notifications and errors on unknown requests."))
+on unknown notifications and errors on unknown requests.
+
+If the symbol `no-unknown-interfaces' is present, Eglot warns at
+compile time if an undeclared LSP interface is used."))
 
 (cl-defun eglot--check-object (interface-name
                                object
@@ -540,7 +553,7 @@ on unknown notifications and errors on unknown requests."))
        for type = (or (cdr (assoc k types)) t) ;; FIXME: enforce nil type?
        unless (cl-typep v type)
        do (eglot--error "A `%s' must have a %s as %s, but has %s"
-                        interface-name )))
+                        interface-name)))
     t))
 
 (eval-and-compile
@@ -587,7 +600,7 @@ on unknown notifications and errors on unknown requests."))
                (when missing-out (byte-compile-warn
                                   "Destructuring for %s is missing out on %s"
                                   interface-name missing-out))))
-            (t
+            ((memq 'no-unknown-interfaces eglot-strict-mode)
              (byte-compile-warn "Unknown LSP interface %s" interface-name))))))
 
 (cl-defmacro eglot--dbind (vars object &body body)
@@ -831,6 +844,9 @@ treated as in `eglot--dbind'."
    (project
     :documentation "Project associated with server."
     :accessor eglot--project)
+   (progress-reporters
+    :initform (make-hash-table :test #'equal) :accessor 
eglot--progress-reporters
+    :documentation "Maps LSP progress tokens to progress reporters.")
    (inhibit-autoreconnect
     :initform t
     :documentation "Generalized boolean inhibiting auto-reconnection if true."
@@ -925,7 +941,7 @@ PRESERVE-BUFFERS as in `eglot-shutdown', which see."
                   (push sym retval))))
     retval))
 
-(defvar eglot--command-history nil
+(defvar eglot-command-history nil
   "History of CONTACT arguments to `eglot'.")
 
 (defun eglot--lookup-mode (mode)
@@ -1125,11 +1141,11 @@ INTERACTIVE is t if called interactively."
   (let ((buffer (current-buffer)))
     (cl-labels
         ((maybe-connect
-          ()
-          (remove-hook 'post-command-hook #'maybe-connect nil)
-          (eglot--when-live-buffer buffer
-            (unless eglot--managed-mode
-              (apply #'eglot--connect (eglot--guess-contact))))))
+           ()
+           (remove-hook 'post-command-hook #'maybe-connect nil)
+           (eglot--when-live-buffer buffer
+             (unless eglot--managed-mode
+               (apply #'eglot--connect (eglot--guess-contact))))))
       (when buffer-file-name
         (add-hook 'post-command-hook #'maybe-connect 'append nil)))))
 
@@ -1181,7 +1197,7 @@ Each function is passed the server as an argument")
       (list "sh" "-c"
             (string-join (cons "stty raw > /dev/null;"
                                (mapcar #'shell-quote-argument contact))
-             " "))
+                         " "))
     contact))
 
 (defvar-local eglot--cached-server nil
@@ -1235,7 +1251,7 @@ This docstring appeases checkdoc, that's all."
                      ,@more-initargs)))))
          (spread (lambda (fn) (lambda (server method params)
                                 (let ((eglot--cached-server server))
-                                 (apply fn server method (append params 
nil))))))
+                                  (apply fn server method (append params 
nil))))))
          (server
           (apply
            #'make-instance class
@@ -1569,7 +1585,7 @@ Doubles as an indicator of snippet support."
       (setq-local markdown-fontify-code-blocks-natively t)
       (insert string)
       (let ((inhibit-message t)
-           (message-log-max nil))
+            (message-log-max nil))
         (ignore-errors (delay-mode-hooks (funcall mode))))
       (font-lock-ensure)
       (string-trim (buffer-string)))))
@@ -1854,8 +1870,8 @@ If it is activated, also signal textDocument/didOpen."
                                            (force-mode-line-update t))))))
 
 (defun eglot-manual () "Open documentation."
-  (declare (obsolete info "29.1"))
-  (interactive) (info "(eglot)"))
+       (declare (obsolete info "29.1"))
+       (interactive) (info "(eglot)"))
 
 (easy-menu-define eglot-menu nil "Eglot"
   `("Eglot"
@@ -1959,17 +1975,17 @@ Uses THING, FACE, DEFS and PREPEND."
            'keymap (let ((map (make-sparse-keymap)))
                      (define-key map [mode-line down-mouse-1] 
eglot-server-menu)
                      map))
-       ,@(when last-error
+         ,@(when last-error
              `("/" ,(eglot--mode-line-props
                      "error" 'compilation-mode-line-fail
                      '((mouse-3 eglot-clear-status  "Clear this status"))
                      (format "An error occurred: %s\n" (plist-get last-error
-                                                                 :message)))))
-       ,@(when (cl-plusp pending)
-           `("/" ,(eglot--mode-line-props
-                   (format "%d" pending) 'warning
-                   '((mouse-3 eglot-forget-pending-continuations
-                              "Forget pending continuations"))
+                                                                  :message)))))
+         ,@(when (cl-plusp pending)
+             `("/" ,(eglot--mode-line-props
+                     (format "%d" pending) 'warning
+                     '((mouse-3 eglot-forget-pending-continuations
+                                "Forget pending continuations"))
                      "Number of outgoing, \
 still unanswered LSP requests to the server\n"))))))))
 
@@ -1987,13 +2003,13 @@ still unanswered LSP requests to the server\n"))))))))
 (defalias 'eglot--diag-data 'flymake-diagnostic-data)
 
 (cl-loop for i from 1
-         for type in '(eglot-note eglot-warning eglot-error )
+         for type in '(eglot-note eglot-warning eglot-error)
          do (put type 'flymake-overlay-control
                  `((mouse-face . highlight)
                    (priority . ,(+ 50 i))
                    (keymap . ,(let ((map (make-sparse-keymap)))
                                 (define-key map [mouse-1]
-                                  (eglot--mouse-call 'eglot-code-actions))
+                                            (eglot--mouse-call 
'eglot-code-actions))
                                 map)))))
 
 
@@ -2049,6 +2065,27 @@ COMMAND is a symbol naming the command."
   (_server (_method (eql telemetry/event)) &rest _any)
   "Handle notification telemetry/event.") ;; noop, use events buffer
 
+(cl-defmethod eglot-handle-notification
+  (server (_method (eql $/progress)) &key token value)
+  "Handle $/progress notification identified by TOKEN from SERVER."
+  (when eglot-report-progress
+    (cl-flet ((fmt (&rest args) (mapconcat #'identity args " ")))
+      (eglot--dbind ((WorkDoneProgress) kind title percentage message) value
+        (pcase kind
+          ("begin"
+           (let* ((prefix (format (concat "[eglot] %s %s:" (when percentage " 
"))
+                                  (eglot-project-nickname server) token))
+                  (pr (puthash token
+                       (if percentage
+                           (make-progress-reporter prefix 0 100 percentage 1 0)
+                         (make-progress-reporter prefix nil nil nil 1 0))
+                       (eglot--progress-reporters server))))
+             (progress-reporter-update pr percentage (fmt title message))))
+          ("report"
+           (when-let ((pr (gethash token (eglot--progress-reporters server))))
+             (progress-reporter-update pr percentage (fmt title message))))
+          ("end" (remhash token (eglot--progress-reporters server))))))))
+
 (cl-defmethod eglot-handle-notification
   (_server (_method (eql textDocument/publishDiagnostics)) &key uri diagnostics
            &allow-other-keys) ; FIXME: doesn't respect `eglot-strict-mode'
@@ -2060,9 +2097,11 @@ COMMAND is a symbol naming the command."
                     (t          'eglot-note)))
             (mess (source code message)
               (concat source (and code (format " [%s]" code)) ": " message)))
-    (if-let ((buffer (find-buffer-visiting (eglot--uri-to-path uri))))
+    (if-let* ((path (expand-file-name (eglot--uri-to-path uri)))
+              (buffer (find-buffer-visiting path)))
         (with-current-buffer buffer
           (cl-loop
+           initially (assoc-delete-all path flymake-list-only-diagnostics 
#'string=)
            for diag-spec across diagnostics
            collect (eglot--dbind ((Diagnostic) range code message severity 
source tags)
                        diag-spec
@@ -2105,7 +2144,6 @@ COMMAND is a symbol naming the command."
                          (t
                           (setq eglot--diagnostics diags)))))
       (cl-loop
-       with path = (expand-file-name (eglot--uri-to-path uri))
        for diag-spec across diagnostics
        collect (eglot--dbind ((Diagnostic) code range message severity source) 
diag-spec
                  (setq message (mess source code message))
@@ -2172,7 +2210,7 @@ THINGS are either registrations or unregisterations 
(sic)."
   (append
    (eglot--VersionedTextDocumentIdentifier)
    (list :languageId
-        (eglot--language-id (eglot--current-server-or-lose))
+         (eglot--language-id (eglot--current-server-or-lose))
          :text
          (eglot--widening
           (buffer-substring-no-properties (point-min) (point-max))))))
@@ -2571,7 +2609,7 @@ If BUFFER, switch to it before."
                   (let ((probe (gethash pat cache :missing)))
                     (if (eq probe :missing) (puthash pat (refresh pat) cache)
                       probe)))
-                (lookup (pat)
+                (lookup (pat _point)
                   (let ((res (lookup-1 pat))
                         (def (and (string= pat "") (gethash :default cache))))
                     (append def res nil)))
@@ -2579,16 +2617,12 @@ If BUFFER, switch to it before."
                   (cl-getf (get-text-property
                             0 'eglot--lsp-workspaceSymbol c)
                            :score 0)))
-      (lambda (string _pred action)
-        (pcase action
-          (`metadata `(metadata
-                       (cycle-sort-function
-                        . ,(lambda (completions)
-                             (cl-sort completions #'> :key #'score)))
-                       (category . eglot-indirection-joy)))
-          (`(eglot--lsp-tryc . ,point) `(eglot--lsp-tryc . (,string . ,point)))
-          (`(eglot--lsp-allc . ,_point) `(eglot--lsp-allc . ,(lookup string)))
-          (_ nil))))))
+      (external-completion-table
+       'eglot-indirection-joy
+       #'lookup
+       `((cycle-sort-function
+          . ,(lambda (completions)
+               (cl-sort completions #'> :key #'score))))))))
 
 (defun eglot--recover-workspace-symbol-meta (string)
   "Search `eglot--workspace-symbols-cache' for rich entry of STRING."
@@ -2600,9 +2634,6 @@ If BUFFER, switch to it before."
                  (setq v (cdr v))))
              eglot--workspace-symbols-cache)))
 
-(add-to-list 'completion-category-overrides
-             '(eglot-indirection-joy (styles . (eglot--lsp-backend-style))))
-
 (cl-defmethod xref-backend-identifier-at-point ((_backend (eql eglot)))
   (let ((attempt
          (and (xref--prompt-p this-command)
@@ -2641,7 +2672,7 @@ If BUFFER, switch to it before."
                                                uri range))))))
        (if (vectorp response) response (and response (list response)))))))
 
-(cl-defun eglot--lsp-xref-helper (method &key extra-params capability )
+(cl-defun eglot--lsp-xref-helper (method &key extra-params capability)
   "Helper for `eglot-find-declaration' & friends."
   (let ((eglot--lsp-xref-refs (eglot--lsp-xrefs-for-method
                                method
@@ -2673,7 +2704,7 @@ If BUFFER, switch to it before."
             (get-text-property 0 'eglot--lsp-workspaceSymbol probe)
           (eglot--dbind ((Location) uri range) location
             (list (eglot--xref-make-match name uri range))))
-        (eglot--lsp-xrefs-for-method :textDocument/definition))))
+      (eglot--lsp-xrefs-for-method :textDocument/definition))))
 
 (cl-defmethod xref-backend-references ((_backend (eql eglot)) _identifier)
   (or
@@ -2712,7 +2743,7 @@ for which LSP on-type-formatting should be requested."
                  `(:textDocument/onTypeFormatting
                    :documentOnTypeFormattingProvider
                    ,`(:position ,(eglot--pos-to-lsp-position beg)
-                      :ch ,(string on-type-format))))
+                                :ch ,(string on-type-format))))
                 ((and beg end)
                  `(:textDocument/rangeFormatting
                    :documentRangeFormattingProvider
@@ -3285,24 +3316,24 @@ at point.  With prefix argument, prompt for 
ACTION-KIND."
                                 (eglot--project server))))))
     (cl-labels
         ((handle-event
-          (event)
-          (pcase-let* ((`(,desc ,action ,file ,file1) event)
-                       (action-type (cl-case action
-                                      (created 1) (changed 2) (deleted 3)))
-                       (action-bit (when action-type
-                                     (ash 1 (1- action-type)))))
-            (cond
-             ((and (memq action '(created changed deleted))
-                   (cl-loop for (glob . kind-bitmask) in globs
-                            thereis (and (> (logand kind-bitmask action-bit) 0)
-                                         (funcall glob file))))
-              (jsonrpc-notify
-               server :workspace/didChangeWatchedFiles
-               `(:changes ,(vector `(:uri ,(eglot--path-to-uri file)
-                                          :type ,action-type)))))
-             ((eq action 'renamed)
-              (handle-event `(,desc 'deleted ,file))
-              (handle-event `(,desc 'created ,file1)))))))
+           (event)
+           (pcase-let* ((`(,desc ,action ,file ,file1) event)
+                        (action-type (cl-case action
+                                       (created 1) (changed 2) (deleted 3)))
+                        (action-bit (when action-type
+                                      (ash 1 (1- action-type)))))
+             (cond
+              ((and (memq action '(created changed deleted))
+                    (cl-loop for (glob . kind-bitmask) in globs
+                             thereis (and (> (logand kind-bitmask action-bit) 
0)
+                                          (funcall glob file))))
+               (jsonrpc-notify
+                server :workspace/didChangeWatchedFiles
+                `(:changes ,(vector `(:uri ,(eglot--path-to-uri file)
+                                           :type ,action-type)))))
+              ((eq action 'renamed)
+               (handle-event `(,desc 'deleted ,file))
+               (handle-event `(,desc 'created ,file1)))))))
       (unwind-protect
           (progn
             (dolist (dir dirs-to-watch)
@@ -3437,42 +3468,6 @@ If NOERROR, return predicate, else erroring function."
                         'eglot-managed-mode-hook "1.6")
 (provide 'eglot)
 
-
-;;; Backend completion
-
-;; Written by Stefan Monnier circa 2016.  Something to move to
-;; minibuffer.el "ASAP" (with all the `eglot--lsp-' replaced by
-;; something else. The very same code already in SLY and stable for a
-;; long time.
-
-;; This "completion style" delegates all the work to the "programmable
-;; completion" table which is then free to implement its own
-;; completion style.  Typically this is used to take advantage of some
-;; external tool which already has its own completion system and
-;; doesn't give you efficient access to the prefix completion needed
-;; by other completion styles.  The table should recognize the symbols
-;; 'eglot--lsp-tryc and 'eglot--lsp-allc as ACTION, reply with
-;; (eglot--lsp-tryc COMP...) or (eglot--lsp-allc . (STRING . POINT)),
-;; accordingly.  tryc/allc names made akward/recognizable on purpose.
-
-(add-to-list 'completion-styles-alist
-             '(eglot--lsp-backend-style
-               eglot--lsp-backend-style-try-completion
-               eglot--lsp-backend-style-all-completions
-               "Ad-hoc completion style provided by the completion table."))
-
-(defun eglot--lsp-backend-style-call (op string table pred point)
-  (when (functionp table)
-    (let ((res (funcall table string pred (cons op point))))
-      (when (eq op (car-safe res))
-        (cdr res)))))
-
-(defun eglot--lsp-backend-style-try-completion (string table pred point)
-  (eglot--lsp-backend-style-call 'eglot--lsp-tryc string table pred point))
-
-(defun eglot--lsp-backend-style-all-completions (string table pred point)
-  (eglot--lsp-backend-style-call 'eglot--lsp-allc string table pred point))
-
 
 ;; Local Variables:
 ;; bug-reference-bug-regexp: "\\(github#\\([0-9]+\\)\\)"
diff --git a/lisp/progmodes/flymake.el b/lisp/progmodes/flymake.el
index adb984c3e5..7af62c3535 100644
--- a/lisp/progmodes/flymake.el
+++ b/lisp/progmodes/flymake.el
@@ -54,9 +54,8 @@
 ;; (question mark) if no backends were even configured.
 ;;
 ;; For programmers interested in writing a new Flymake backend, the
-;; docstring of `flymake-diagnostic-functions', the Flymake manual,
-;; and the code of existing backends are probably a good starting
-;; point.
+;; docstring of `flymake-diagnostic-functions', the Flymake manual, and the
+;; code of existing backends are probably good starting points.
 ;;
 ;; The user wishing to customize the appearance of error types should
 ;; set properties on the symbols associated with each diagnostic type.
@@ -1636,6 +1635,7 @@ buffer."
 (define-derived-mode flymake-diagnostics-buffer-mode tabulated-list-mode
   "Flymake diagnostics"
   "A mode for listing Flymake diagnostics."
+  :interactive nil
   (setq tabulated-list-format flymake--diagnostics-base-tabulated-list-format)
   (setq tabulated-list-entries
         'flymake--diagnostics-buffer-entries)
@@ -1693,6 +1693,7 @@ some of this variable's contents the diagnostic 
listings.")
 (define-derived-mode flymake-project-diagnostics-mode tabulated-list-mode
   "Flymake diagnostics"
   "A mode for listing Flymake diagnostics."
+  :interactive nil
   (setq tabulated-list-format
         (vconcat [("File" 25 t)]
                  flymake--diagnostics-base-tabulated-list-format))
diff --git a/lisp/progmodes/gdb-mi.el b/lisp/progmodes/gdb-mi.el
index e8d8f9104e..ff14546c63 100644
--- a/lisp/progmodes/gdb-mi.el
+++ b/lisp/progmodes/gdb-mi.el
@@ -1113,13 +1113,13 @@ no input, and GDB is waiting for input."
              (process-live-p proc)
             (not gud-running)
             (= (point) (marker-position (process-mark proc))))
-       ;; Sending an EOF does not work with GDB-MI; submit an
-       ;; explicit quit command.
-       (progn
-          (if (> gdb-control-level 0)
-              (process-send-eof proc)
-            (insert "quit")
-            (comint-send-input t t)))
+      ;; Exit a recursive reading loop or quit.
+      (if (> gdb-control-level 0)
+          (process-send-eof proc)
+        ;; Sending an EOF does not work with GDB-MI; submit an
+        ;; explicit quit command.
+        (insert "quit")
+        (comint-send-input t t))
       (delete-char arg))))
 
 (defvar gdb-define-alist nil "Alist of #define directives for GUD tooltips.")
@@ -4355,6 +4355,24 @@ member."
   :group 'gud
   :version "29.1")
 
+(defcustom gdb-locals-table-row-config `((name . 20)
+                                         (type . 20)
+                                         (value . ,gdb-locals-value-limit))
+  "Configuration for table rows in the local variable display.
+
+An alist that controls the display of the name, type and value of
+local variables inside the currently active stack-frame.  The key
+controls which column to change whereas the value determines the
+maximum number of characters to display in each column.  A value
+of 0 means there is no limit.
+
+Additionally, the order the element in the alist determines the
+left-to-right display order of the properties."
+  :type '(alist :key-type symbol :value-type integer)
+  :group 'gud
+  :version "30.1")
+
+
 (defvar gdb-locals-values-table (make-hash-table :test #'equal)
   "Mapping of local variable names to a string with their value.")
 
@@ -4384,12 +4402,9 @@ member."
 
 (defun gdb-locals-value-filter (value)
   "Filter function for the local variable VALUE."
-  (let* ((no-nl (replace-regexp-in-string "\n" " " value))
-         (str (replace-regexp-in-string "[[:space:]]+" " " no-nl))
-         (limit gdb-locals-value-limit))
-    (if (>= (length str) limit)
-        (concat (substring str 0 limit) "...")
-      str)))
+  (let* ((no-nl (replace-regexp-in-string "\n" " " (or value "<Unknown>")))
+         (str (replace-regexp-in-string "[[:space:]]+" " " no-nl)))
+    str))
 
 (defun gdb-edit-locals-value (&optional event)
   "Assign a value to a variable displayed in the locals buffer."
@@ -4403,6 +4418,22 @@ member."
       (gud-basic-call
        (concat  "-gdb-set variable " var " = " value)))))
 
+
+(defun gdb-locals-table-columns-list (alist)
+  "Format and arrange the columns in locals display based on ALIST."
+  (let (columns)
+    (dolist (config gdb-locals-table-row-config columns)
+      (let* ((key  (car config))
+             (max  (cdr config))
+             (prop (alist-get key alist)))
+        (when prop
+          (if (and (> max 0) (length> prop max))
+              (push (propertize (string-truncate-left prop max) 'help-echo 
prop)
+                    columns)
+            (push prop columns)))))
+    (nreverse columns)))
+
+
 ;; Complex data types are looked up in `gdb-locals-values-table'.
 (defun gdb-locals-handler-custom ()
   "Handler to rebuild the local variables table buffer."
@@ -4431,12 +4462,14 @@ member."
                                             help-echo "mouse-2: edit value"
                                             local-map ,gdb-edit-locals-map-1)
                                value))
+        (setf (gdb-table-right-align table) t)
+        (setq name (propertize name 'font-lock-face 
font-lock-variable-name-face))
+        (setq type (propertize type 'font-lock-face font-lock-type-face))
         (gdb-table-add-row
          table
-         (list
-          (propertize type 'font-lock-face font-lock-type-face)
-          (propertize name 'font-lock-face font-lock-variable-name-face)
-          value)
+         (gdb-locals-table-columns-list `((name  . ,name)
+                                          (type  . ,type)
+                                          (value . ,value)))
          `(gdb-local-variable ,local))))
     (insert (gdb-table-string table " "))
     (setq mode-name
@@ -5124,6 +5157,8 @@ This arrangement depends on the values of variable
 (defun gdb-reset ()
   "Exit a debugging session cleanly.
 Kills the gdb buffers, and resets variables and the source buffers."
+  ;; Save GDB history
+  (comint-write-input-ring)
   ;; The gdb-inferior buffer has a pty hooked up to the main gdb
   ;; process.  This pty must be deleted explicitly.
   (let ((pty (get-process "gdb-inferior")))
diff --git a/lisp/progmodes/go-ts-mode.el b/lisp/progmodes/go-ts-mode.el
new file mode 100644
index 0000000000..124d9b044a
--- /dev/null
+++ b/lisp/progmodes/go-ts-mode.el
@@ -0,0 +1,354 @@
+;;; go-ts-mode.el --- tree-sitter support for Go  -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author     : Randy Taylor <dev@rjt.dev>
+;; Maintainer : Randy Taylor <dev@rjt.dev>
+;; Created    : December 2022
+;; Keywords   : go languages tree-sitter
+
+;; 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:
+;;
+
+;;; Code:
+
+(require 'treesit)
+(eval-when-compile (require 'rx))
+
+(declare-function treesit-parser-create "treesit.c")
+(declare-function treesit-induce-sparse-tree "treesit.c")
+(declare-function treesit-node-child "treesit.c")
+(declare-function treesit-node-child-by-field-name "treesit.c")
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
+
+(defcustom go-ts-mode-indent-offset 4
+  "Number of spaces for each indentation step in `go-ts-mode'."
+  :version "29.1"
+  :type 'integer
+  :safe 'integerp
+  :group 'go)
+
+(defvar go-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?+   "."      table)
+    (modify-syntax-entry ?-   "."      table)
+    (modify-syntax-entry ?=   "."      table)
+    (modify-syntax-entry ?%   "."      table)
+    (modify-syntax-entry ?&   "."      table)
+    (modify-syntax-entry ?|   "."      table)
+    (modify-syntax-entry ?^   "."      table)
+    (modify-syntax-entry ?!   "."      table)
+    (modify-syntax-entry ?<   "."      table)
+    (modify-syntax-entry ?>   "."      table)
+    (modify-syntax-entry ?\\  "\\"     table)
+    (modify-syntax-entry ?/   ". 124b" table)
+    (modify-syntax-entry ?*   ". 23"   table)
+    (modify-syntax-entry ?\n  "> b"    table)
+    table)
+  "Syntax table for `go-ts-mode'.")
+
+(defvar go-ts-mode--indent-rules
+  `((go
+     ((node-is ")") parent-bol 0)
+     ((node-is "]") parent-bol 0)
+     ((node-is "}") parent-bol 0)
+     ((node-is "labeled_statement") no-indent)
+     ((parent-is "argument_list") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "block") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "const_declaration") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "default_case") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "expression_case") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "expression_switch_statement") parent-bol 0)
+     ((parent-is "field_declaration_list") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "import_spec_list") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "labeled_statement") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "literal_value") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "type_spec") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "var_declaration") parent-bol go-ts-mode-indent-offset)
+     (no-node parent-bol 0)))
+  "Tree-sitter indent rules for `go-ts-mode'.")
+
+(defvar go-ts-mode--keywords
+  '("break" "case" "chan" "const" "continue" "default" "defer" "else"
+    "fallthrough" "for" "func" "go" "goto" "if" "import" "interface" "map"
+    "package" "range" "return" "select" "struct" "switch" "type" "var")
+  "Go keywords for tree-sitter font-locking.")
+
+(defvar go-ts-mode--operators
+  '("+" "&" "+=" "&=" "&&" "==" "!=" "-" "|" "-=" "|=" "||" "<" "<="
+    "*" "^" "*=" "^=" "<-" ">" ">=" "/" "<<" "/=" "<<=" "++" "=" ":=" "%"
+    ">>" "%=" ">>=" "--" "!"  "..."  "&^" "&^=" "~")
+  "Go operators for tree-sitter font-locking.")
+
+(defvar go-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'go
+   :feature 'bracket
+   '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
+
+   :language 'go
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
+
+   :language 'go
+   :feature 'constant
+   '([(false) (iota) (nil) (true)] @font-lock-constant-face
+     (const_declaration
+      (const_spec name: (identifier) @font-lock-constant-face)))
+
+   :language 'go
+   :feature 'delimiter
+   '((["," "." ";" ":"]) @font-lock-delimiter-face)
+
+   :language 'go
+   :feature 'function
+   '((call_expression
+      function: (identifier) @font-lock-function-name-face)
+     (call_expression
+      function: (selector_expression
+                 field: (field_identifier) @font-lock-function-name-face))
+     (function_declaration
+      name: (identifier) @font-lock-function-name-face)
+     (method_declaration
+      name: (field_identifier) @font-lock-function-name-face))
+
+   :language 'go
+   :feature 'keyword
+   `([,@go-ts-mode--keywords] @font-lock-keyword-face)
+
+   :language 'go
+   :feature 'label
+   '((label_name) @font-lock-constant-face)
+
+   :language 'go
+   :feature 'number
+   '([(float_literal)
+      (imaginary_literal)
+      (int_literal)] @font-lock-number-face)
+
+   :language 'go
+   :feature 'string
+   '([(interpreted_string_literal)
+      (raw_string_literal)
+      (rune_literal)] @font-lock-string-face)
+
+   :language 'go
+   :feature 'type
+   '([(package_identifier) (type_identifier)] @font-lock-type-face)
+
+   :language 'go
+   :feature 'variable
+   '((identifier) @font-lock-variable-name-face)
+
+   :language 'go
+   :feature 'escape-sequence
+   :override t
+   '((escape_sequence) @font-lock-escape-face)
+
+   :language 'go
+   :feature 'property
+   :override t
+   '((field_identifier) @font-lock-property-face
+     (keyed_element (_ (identifier) @font-lock-property-face)))
+
+   :language 'go
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Tree-sitter font-lock settings for `go-ts-mode'.")
+
+(defun go-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (func-tree (treesit-induce-sparse-tree
+                     node "function_declaration" nil 1000))
+         (type-tree (treesit-induce-sparse-tree
+                     node "type_spec" nil 1000))
+         (func-index (go-ts-mode--imenu-1 func-tree))
+         (type-index (go-ts-mode--imenu-1 type-tree)))
+    (append
+     (when func-index `(("Function" . ,func-index)))
+     (when type-index `(("Type" . ,type-index))))))
+
+(defun go-ts-mode--imenu-1 (node)
+  "Helper for `go-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (children (cdr node))
+         (subtrees (mapcan #'go-ts-mode--imenu-1
+                           children))
+         (name (when ts-node
+                 (treesit-node-text
+                  (pcase (treesit-node-type ts-node)
+                    ("function_declaration"
+                     (treesit-node-child-by-field-name ts-node "name"))
+                    ("type_spec"
+                     (treesit-node-child-by-field-name ts-node "name"))))))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((or (null ts-node) (null name)) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
+
+;;;###autoload
+(define-derived-mode go-ts-mode prog-mode "Go"
+  "Major mode for editing Go, powered by tree-sitter."
+  :group 'go
+  :syntax-table go-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'go)
+    (treesit-parser-create 'go)
+
+    ;; Comments.
+    (setq-local comment-start "// ")
+    (setq-local comment-end "")
+    (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
+
+    ;; Imenu.
+    (setq-local imenu-create-index-function #'go-ts-mode--imenu)
+    (setq-local which-func-functions nil)
+
+    ;; Indent.
+    (setq-local indent-tabs-mode t
+                treesit-simple-indent-rules go-ts-mode--indent-rules)
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings go-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '(( comment)
+                  ( keyword string type)
+                  ( constant escape-sequence function label number
+                    property variable)
+                  ( bracket delimiter error operator)))
+
+    (treesit-major-mode-setup)))
+
+;; go.mod support.
+
+(defvar go-mod-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?/   ". 124b" table)
+    (modify-syntax-entry ?\n  "> b"    table)
+    table)
+  "Syntax table for `go-mod-ts-mode'.")
+
+(defvar go-mod-ts-mode--indent-rules
+  `((gomod
+     ((node-is ")") parent-bol 0)
+     ((parent-is "exclude_directive") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "module_directive") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "replace_directive") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "require_directive") parent-bol go-ts-mode-indent-offset)
+     ((parent-is "retract_directive") parent-bol go-ts-mode-indent-offset)
+     ((go-mod-ts-mode--in-directive-p) no-indent go-ts-mode-indent-offset)
+     (no-node no-indent 0)))
+  "Tree-sitter indent rules for `go-mod-ts-mode'.")
+
+(defun go-mod-ts-mode--in-directive-p ()
+  "Return non-nil if inside a directive.
+When entering an empty directive or adding a new entry to one, no node
+will be present meaning none of the indentation rules will match,
+because there is no parent to match against.  This function determines
+what the parent of the node would be if it were a node."
+  (lambda (node _ _ &rest _)
+    (unless (treesit-node-type node)
+      (save-excursion
+        (backward-up-list)
+        (back-to-indentation)
+        (pcase (treesit-node-type (treesit-node-at (point)))
+          ("exclude" t)
+          ("module" t)
+          ("replace" t)
+          ("require" t)
+          ("retract" t))))))
+
+(defvar go-mod-ts-mode--keywords
+  '("exclude" "go" "module" "replace" "require" "retract")
+  "go.mod keywords for tree-sitter font-locking.")
+
+(defvar go-mod-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'gomod
+   :feature 'bracket
+   '((["(" ")"]) @font-lock-bracket-face)
+
+   :language 'gomod
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
+
+   :language 'gomod
+   :feature 'keyword
+   `([,@go-mod-ts-mode--keywords] @font-lock-keyword-face)
+
+   :language 'gomod
+   :feature 'number
+   '([(go_version) (version)] @font-lock-number-face)
+
+   :language 'gomod
+   :feature 'operator
+   '((["=>"]) @font-lock-operator-face)
+
+   :language 'gomod
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Tree-sitter font-lock settings for `go-mod-ts-mode'.")
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("/go\\.mod\\'" . go-mod-ts-mode))
+
+;;;###autoload
+(define-derived-mode go-mod-ts-mode prog-mode "Go Mod"
+  "Major mode for editing go.mod files, powered by tree-sitter."
+  :group 'go
+  :syntax-table go-mod-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'gomod)
+    (treesit-parser-create 'gomod)
+
+    ;; Comments.
+    (setq-local comment-start "// ")
+    (setq-local comment-end "")
+    (setq-local comment-start-skip (rx "//" (* (syntax whitespace))))
+
+    ;; Indent.
+    (setq-local indent-tabs-mode t
+                treesit-simple-indent-rules go-mod-ts-mode--indent-rules)
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings go-mod-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '((comment)
+                  (keyword)
+                  (number)
+                  (bracket error operator)))
+
+    (treesit-major-mode-setup)))
+
+(provide 'go-ts-mode)
+
+;;; go-ts-mode.el ends here
diff --git a/lisp/progmodes/grep.el b/lisp/progmodes/grep.el
index 2446e86abb..35cac43bee 100644
--- a/lisp/progmodes/grep.el
+++ b/lisp/progmodes/grep.el
@@ -1254,6 +1254,10 @@ or not."
                                          nil default-directory t))
                (confirm (equal current-prefix-arg '(4))))
           (list regexp files dir confirm))))))
+  ;; If called non-interactively, also compute the defaults if we
+  ;; haven't already.
+  (unless grep-find-template
+    (grep-compute-defaults))
   (when (and (stringp regexp) (> (length regexp) 0))
     (unless (and dir (file-accessible-directory-p dir))
       (setq dir default-directory))
diff --git a/lisp/progmodes/idlwave.el b/lisp/progmodes/idlwave.el
index cd2fc7c707..395c51d542 100644
--- a/lisp/progmodes/idlwave.el
+++ b/lisp/progmodes/idlwave.el
@@ -133,7 +133,7 @@
 ;;   limited to comments only and occurs only when a comment
 ;;   paragraph is filled via `idlwave-fill-paragraph'.
 ;;
-;;   Muti-statement lines (using "&") on block begin and end lines can
+;;   Multi-statement lines (using "&") on block begin and end lines can
 ;;   ruin the formatting.  For example, multiple end statements on a
 ;;   line: endif & endif.  Using "&" outside of block begin/end lines
 ;;   should be okay.
diff --git a/lisp/progmodes/java-ts-mode.el b/lisp/progmodes/java-ts-mode.el
index 2c42505ac9..bd6a8aa474 100644
--- a/lisp/progmodes/java-ts-mode.el
+++ b/lisp/progmodes/java-ts-mode.el
@@ -9,19 +9,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
@@ -58,6 +57,11 @@
     (modify-syntax-entry ?|  "."     table)
     (modify-syntax-entry ?\' "\""    table)
     (modify-syntax-entry ?\240 "."   table)
+    (modify-syntax-entry ?/  ". 124b" table)
+    (modify-syntax-entry ?*  ". 23"   table)
+    (modify-syntax-entry ?\n "> b"  table)
+    (modify-syntax-entry ?\^m "> b" table)
+    (modify-syntax-entry ?@ "'" table)
     table)
   "Syntax table for `java-ts-mode'.")
 
@@ -69,6 +73,7 @@
      ((node-is "]") parent-bol 0)
      ((and (parent-is "comment") comment-end) comment-start -1)
      ((parent-is "comment") comment-start-skip 0)
+     ((parent-is "text_block") no-indent)
      ((parent-is "class_body") parent-bol java-ts-mode-indent-offset)
      ((parent-is "interface_body") parent-bol java-ts-mode-indent-offset)
      ((parent-is "constructor_body") parent-bol java-ts-mode-indent-offset)
@@ -81,6 +86,7 @@
      ((parent-is "method_invocation") parent-bol java-ts-mode-indent-offset)
      ((parent-is "switch_rule") parent-bol java-ts-mode-indent-offset)
      ((parent-is "ternary_expression") parent-bol java-ts-mode-indent-offset)
+     ((parent-is "lambda_expression") parent-bol java-ts-mode-indent-offset)
      ((parent-is "element_value_array_initializer") parent-bol 
java-ts-mode-indent-offset)
      ((parent-is "function_definition") parent-bol 0)
      ((parent-is "conditional_expression") first-sibling 0)
@@ -114,14 +120,14 @@
     "static" "strictfp" "switch" "synchronized"
     "throw" "throws" "to" "transient" "transitive"
     "try" "uses" "volatile" "while" "with" "record")
-  "C keywords for tree-sitter font-locking.")
+  "Java keywords for tree-sitter font-locking.")
 
 (defvar java-ts-mode--operators
   '("+" ":" "++" "-" "--" "&" "&&" "|" "||" "="
     "!=" "==" "*" "/" "%" "<" "<=" ">" ">="
     "-=" "+=" "*=" "/=" "%=" "->" "^" "^="
     "|=" "~" ">>" ">>>" "<<" "::" "?" "&=")
-  "C operators for tree-sitter font-locking.")
+  "Java operators for tree-sitter font-locking.")
 
 (defvar java-ts-mode--font-lock-settings
   (treesit-font-lock-rules
@@ -139,9 +145,10 @@
    :language 'java
    :override t
    :feature 'keyword
-   `([,@java-ts-mode--keywords] @font-lock-keyword-face
-     (labeled_statement
-      (identifier) @font-lock-keyword-face))
+   `([,@java-ts-mode--keywords
+      (this)] @font-lock-keyword-face
+      (labeled_statement
+       (identifier) @font-lock-keyword-face))
    :language 'java
    :override t
    :feature 'operator
@@ -158,7 +165,8 @@
    :language 'java
    :override t
    :feature 'string
-   `((string_literal) @font-lock-string-face)
+   `((string_literal) @font-lock-string-face
+     (text_block) @font-lock-string-face)
    :language 'java
    :override t
    :feature 'literal
@@ -238,7 +246,7 @@
    :language 'java
    :feature 'delimiter
    '((["," ":" ";"]) @font-lock-delimiter-face))
-  "Tree-sitter font-lock settings.")
+  "Tree-sitter font-lock settings for `java-ts-mode'.")
 
 (defun java-ts-mode--imenu-1 (node)
   "Helper for `java-ts-mode--imenu'.
@@ -309,6 +317,11 @@ the subtrees."
                   (group (or (syntax comment-end)
                              (seq (+ "*") "/")))))
 
+  (setq-local treesit-text-type-regexp
+              (regexp-opt '("line_comment"
+                            "block_comment"
+                            "text_block")))
+
   ;; Indent.
   (setq-local treesit-simple-indent-rules java-ts-mode--indent-rules)
 
@@ -317,7 +330,15 @@ the subtrees."
               (append "{}():;," electric-indent-chars))
 
   ;; Navigation.
-  (setq-local treesit-defun-type-regexp "declaration")
+  (setq-local treesit-defun-type-regexp
+              (regexp-opt '("method_declaration"
+                            "class_declaration"
+                            "record_declaration"
+                            "interface_declaration"
+                            "enum_declaration"
+                            "import_declaration"
+                            "package_declaration"
+                            "module_declaration")))
 
   ;; Font-lock.
   (setq-local treesit-font-lock-settings java-ts-mode--font-lock-settings)
diff --git a/lisp/progmodes/js.el b/lisp/progmodes/js.el
index 90ab7cc924..cbcca81baa 100644
--- a/lisp/progmodes/js.el
+++ b/lisp/progmodes/js.el
@@ -686,7 +686,7 @@ This variable is like `sgml-attribute-offset'."
     (modify-syntax-entry ?$ "_" table)
     (modify-syntax-entry ?` "\"" table)
     table)
-  "Syntax table for `js-mode'.")
+  "Syntax table for `js-mode' and `js-ts-mode'.")
 
 (defvar-local js--quick-match-re nil
   "Autogenerated regexp used by `js-mode' to match buffer constructs.")
@@ -1928,7 +1928,7 @@ This performs fontification according to 
`js--class-styles'."
 ;; identified as such), then the `syntax-propertize' region won’t be
 ;; extended backwards to the start of the JSXOpeningElement:
 ;;
-;;   <div         ← This line wasn’t JSX when last edited.
+;;   <div         ← This line wasn't JSX when last edited.
 ;;     attr="">   ← Despite completing the JSX, the next
 ;;             ^    `syntax-propertize' region wouldn’t magically
 ;;                  extend back a few lines.
@@ -2090,7 +2090,7 @@ JSXElement or a JSXOpeningElement/JSXClosingElement pair."
                         ;; JSXOpeningElement has been found, so keep
                         ;; looking backwards for an enclosing one).
                         (or (not close-tag-pos) (<= start 
close-tag-pos)))))))))
-      ;; Don’t return the last tag pos, as it wasn’t enclosing.
+      ;; Don't return the last tag pos, as it wasn't enclosing.
       (setq tag-beg nil close-tag-pos nil))
     (and tag-beg (list tag-beg-pos tag-end-pos close-tag-pos))))
 
@@ -3445,17 +3445,19 @@ This function is intended for use in 
`after-change-functions'."
        ((parent-is "pair") parent-bol js-indent-level)
        ((parent-is "arrow_function") parent-bol js-indent-level)
        ((parent-is "parenthesized_expression") parent-bol js-indent-level)
+       ((parent-is "binary_expression") parent-bol js-indent-level)
        ((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)
 
        ;; JSX
-       ((parent-is "jsx_opening_element") parent js-indent-level)
+       ((node-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
+       ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
+       ((node-is "jsx_expression") parent typescript-ts-mode-indent-offset)
+       ((node-is "jsx_self_closing_element") parent 
typescript-ts-mode-indent-offset)
        ((node-is "jsx_closing_element") parent 0)
-       ((node-is "jsx_text") parent js-indent-level)
-       ((parent-is "jsx_element") parent js-indent-level)
        ((node-is "/") parent 0)
-       ((parent-is "jsx_self_closing_element") parent js-indent-level)))))
+       ((node-is ">") parent 0)))))
 
 (defvar js--treesit-keywords
   '("as" "async" "await" "break" "case" "catch" "class" "const" "continue"
@@ -3543,6 +3545,20 @@ This function is intended for use in 
`after-change-functions'."
      (arrow_function
       parameter: (identifier) @font-lock-variable-name-face))
 
+   :language 'javascript
+   :override t
+   :feature 'property
+   ;; This needs to be before function-name feature, because methods
+   ;; can be both property and function-name, and we want them in
+   ;; function-name face.
+   `((property_identifier) @font-lock-property-face
+
+     (pair value: (identifier) @font-lock-variable-name-face)
+
+     ((shorthand_property_identifier) @font-lock-property-face)
+
+     ((shorthand_property_identifier_pattern) @font-lock-property-face))
+
    :language 'javascript
    :override t
    :feature 'expression
@@ -3611,18 +3627,7 @@ This function is intended for use in 
`after-change-functions'."
    :language 'javascript
    :feature 'escape-sequence
    :override t
-   '((escape_sequence) @font-lock-escape-face)
-
-   :language 'javascript
-   :override t
-   :feature 'property
-   `((property_identifier) @font-lock-property-face
-
-     (pair value: (identifier) @font-lock-variable-name-face)
-
-     ((shorthand_property_identifier) @font-lock-property-face)
-
-     ((shorthand_property_identifier_pattern) @font-lock-property-face)))
+   '((escape_sequence) @font-lock-escape-face))
   "Tree-sitter font-lock settings.")
 
 (defun js--fontify-template-string (node override start end &rest _)
@@ -3734,7 +3739,7 @@ definition*\"."
          (var-tree (treesit-induce-sparse-tree
                     node "lexical_declaration" nil 1000)))
     `(("Class" . ,(js--treesit-imenu-1 class-tree))
-      ("Varieable" . ,(js--treesit-imenu-1 var-tree))
+      ("Variable" . ,(js--treesit-imenu-1 var-tree))
       ("Function" . ,(js--treesit-imenu-1 func-tree)))))
 
 ;;; Main Function
@@ -3840,6 +3845,7 @@ Currently there are `js-mode' and `js-ts-mode'."
 
 \\<js-ts-mode-map>"
   :group 'js
+  :syntax-table js-mode-syntax-table
   (when (treesit-ready-p 'javascript)
     ;; Borrowed from `js-mode'.
     (setq-local prettify-symbols-alist js--prettify-symbols-alist)
@@ -3857,6 +3863,11 @@ Currently there are `js-mode' and `js-ts-mode'."
                     (group (or (syntax comment-end)
                                (seq (+ "*") "/")))))
     (setq-local comment-multi-line t)
+
+    (setq-local treesit-text-type-regexp
+                (regexp-opt '("comment"
+                              "template_string")))
+
     ;; Electric-indent.
     (setq-local electric-indent-chars
                (append "{}():;," electric-indent-chars)) ;FIXME: js2-mode adds 
"[]*".
@@ -3868,6 +3879,7 @@ Currently there are `js-mode' and `js-ts-mode'."
     ;; Indent.
     (setq-local treesit-simple-indent-rules js--treesit-indent-rules)
     ;; Navigation.
+    (setq-local treesit-defun-prefer-top-level t)
     (setq-local treesit-defun-type-regexp
                 (rx (or "class_declaration"
                         "method_definition"
diff --git a/lisp/progmodes/json-ts-mode.el b/lisp/progmodes/json-ts-mode.el
index 101e873cf6..6c2f380587 100644
--- a/lisp/progmodes/json-ts-mode.el
+++ b/lisp/progmodes/json-ts-mode.el
@@ -9,19 +9,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
@@ -46,9 +45,7 @@
 
 (defvar json-ts-mode--syntax-table
   (let ((table (make-syntax-table)))
-    ;; Taken from the cc-langs version
     (modify-syntax-entry ?_  "_"     table)
-    (modify-syntax-entry ?$ "_"      table)
     (modify-syntax-entry ?\\ "\\"    table)
     (modify-syntax-entry ?+  "."     table)
     (modify-syntax-entry ?-  "."     table)
@@ -58,8 +55,12 @@
     (modify-syntax-entry ?>  "."     table)
     (modify-syntax-entry ?&  "."     table)
     (modify-syntax-entry ?|  "."     table)
-    (modify-syntax-entry ?` "\""     table)
+    (modify-syntax-entry ?\' "\""    table)
     (modify-syntax-entry ?\240 "."   table)
+    (modify-syntax-entry ?/  ". 124b" table)
+    (modify-syntax-entry ?*  ". 23"   table)
+    (modify-syntax-entry ?\n "> b"  table)
+    (modify-syntax-entry ?\^m "> b" table)
     table)
   "Syntax table for `json-ts-mode'.")
 
@@ -69,10 +70,14 @@
      ((node-is "}") parent-bol 0)
      ((node-is ")") parent-bol 0)
      ((node-is "]") parent-bol 0)
-     ((parent-is "object") parent-bol json-ts-mode-indent-offset))))
+     ((parent-is "object") parent-bol json-ts-mode-indent-offset)
+     ((parent-is "array") parent-bol json-ts-mode-indent-offset))))
 
 (defvar json-ts-mode--font-lock-settings
   (treesit-font-lock-rules
+   :language 'json
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
    :language 'json
    :feature 'bracket
    '((["[" "]" "{" "}"]) @font-lock-bracket-face)
@@ -93,6 +98,10 @@
    :override t
    '((escape_sequence) @font-lock-escape-face)
    :language 'json
+   :feature 'pair
+   :override t ; Needed for overriding string face on keys.
+   '((pair key: (_) @font-lock-variable-name-face))
+   :language 'json
    :feature 'error
    :override t
    '((ERROR) @font-lock-warning-face))
@@ -156,7 +165,7 @@ the subtrees."
   ;; Font-lock.
   (setq-local treesit-font-lock-settings json-ts-mode--font-lock-settings)
   (setq-local treesit-font-lock-feature-list
-              '((constant number string)
+              '((comment constant number pair string)
                 (escape-sequence)
                 (bracket delimiter error)))
 
diff --git a/lisp/progmodes/prog-mode.el b/lisp/progmodes/prog-mode.el
index 58cb48f182..aa37a4ac86 100644
--- a/lisp/progmodes/prog-mode.el
+++ b/lisp/progmodes/prog-mode.el
@@ -30,7 +30,12 @@
 ;;; Code:
 
 (eval-when-compile (require 'cl-lib)
-                   (require 'subr-x))
+                   (require 'subr-x)
+                   (require 'treesit))
+
+(declare-function treesit-available-p "treesit.c")
+(declare-function treesit-parser-list "treesit.c")
+(declare-function treesit-node-type "treesit.c")
 
 (defgroup prog-mode nil
   "Generic programming mode, from which others derive."
@@ -102,7 +107,8 @@
 
 (defvar-keymap prog-mode-map
   :doc "Keymap used for programming modes."
-  "C-M-q" #'prog-indent-sexp)
+  "C-M-q" #'prog-indent-sexp
+  "M-q" #'prog-fill-reindent-defun)
 
 (defvar prog-indentation-context nil
   "When non-nil, provides context for indenting embedded code chunks.
@@ -140,6 +146,33 @@ instead."
          (end (progn (forward-sexp 1) (point))))
       (indent-region start end nil))))
 
+(defun prog-fill-reindent-defun (&optional argument)
+  "Refill or reindent the paragraph or defun that contains point.
+
+If the point is in a string or a comment, fill the paragraph that
+contains point or follows point.
+
+Otherwise, reindent the function definition that contains point
+or follows point."
+  (interactive "P")
+  (save-excursion
+    (let ((treesit-text-node
+           (and (treesit-available-p)
+                (treesit-parser-list)
+                (string-match-p
+                 treesit-text-type-regexp
+                 (treesit-node-type (treesit-node-at (point)))))))
+      (if (or treesit-text-node
+              (nth 8 (syntax-ppss))
+              (re-search-forward comment-start-skip (line-end-position) t))
+          (if (memq fill-paragraph-function '(t nil))
+              (lisp-fill-paragraph argument)
+            (funcall fill-paragraph-function argument))
+        (beginning-of-defun)
+        (let ((start (point)))
+          (end-of-defun)
+          (indent-region start (point) nil))))))
+
 (defun prog-first-column ()
   "Return the indentation column normally used for top-level constructs."
   (or (car prog-indentation-context) 0))
diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el
index 38d4fdad5f..559da6dd64 100644
--- a/lisp/progmodes/project.el
+++ b/lisp/progmodes/project.el
@@ -1,7 +1,7 @@
 ;;; project.el --- Operations on the current project  -*- lexical-binding: t; 
-*-
 
 ;; Copyright (C) 2015-2022 Free Software Foundation, Inc.
-;; Version: 0.9.2
+;; Version: 0.9.3
 ;; Package-Requires: ((emacs "26.1") (xref "1.4.0"))
 
 ;; This is a GNU ELPA :core package.  Avoid using functionality that
@@ -174,6 +174,7 @@
 ;;; Code:
 
 (require 'cl-generic)
+(require 'cl-lib)
 (require 'seq)
 (eval-when-compile (require 'subr-x))
 
@@ -515,7 +516,8 @@ project backend implementation of 
`project-external-roots'.")
              (marker-re
               (mapconcat
                (lambda (m) (format "\\(%s\\)" (wildcard-to-regexp m)))
-               (append backend-markers project-vc-extra-root-markers)
+               (append backend-markers
+                       (project--value-in-dir 'project-vc-extra-root-markers 
dir))
                "\\|"))
              (locate-dominating-stop-dir-regexp
               (or vc-ignore-dir-regexp locate-dominating-stop-dir-regexp))
@@ -535,7 +537,7 @@ project backend implementation of 
`project-external-roots'.")
              project)
         (when (and
                (eq backend 'Git)
-               project-vc-merge-submodules
+               (project--vc-merge-submodules-p root)
                (project--submodule-p root))
           (let* ((parent (file-name-directory (directory-file-name root))))
             (setq root (vc-call-backend 'Git 'root parent))))
@@ -582,7 +584,7 @@ project backend implementation of 
`project-external-roots'.")
 (cl-defmethod project-files ((project (head vc)) &optional dirs)
   (mapcan
    (lambda (dir)
-     (let ((ignores project-vc-ignores)
+     (let ((ignores (project--value-in-dir 'project-vc-ignores (nth 2 
project)))
            (backend (cadr project)))
        (when backend
          (require (intern (concat "vc-" (downcase (symbol-name backend))))))
@@ -608,13 +610,16 @@ project backend implementation of 
`project-external-roots'.")
   (defvar vc-git-use-literal-pathspecs)
   (pcase backend
     (`Git
-     (let ((default-directory (expand-file-name (file-name-as-directory dir)))
-           (args '("-z"))
-           (vc-git-use-literal-pathspecs nil)
-           files)
+     (let* ((default-directory (expand-file-name (file-name-as-directory dir)))
+            (args '("-z"))
+            (vc-git-use-literal-pathspecs nil)
+            (include-untracked (project--value-in-dir
+                                'project-vc-include-untracked
+                                dir))
+            files)
        (setq args (append args
                           '("-c" "--exclude-standard")
-                          (and project-vc-include-untracked '("-o"))))
+                          (and include-untracked '("-o"))))
        (when extra-ignores
          (setq args (append args
                             (cons "--"
@@ -647,7 +652,7 @@ project backend implementation of 
`project-external-roots'.")
               (split-string
                (apply #'vc-git--run-command-string nil "ls-files" args)
                "\0" t)))
-       (when project-vc-merge-submodules
+       (when (project--vc-merge-submodules-p default-directory)
          ;; Unfortunately, 'ls-files --recurse-submodules' conflicts with '-o'.
          (let* ((submodules (project--git-submodules))
                 (sub-files
@@ -665,10 +670,13 @@ project backend implementation of 
`project-external-roots'.")
        ;; XXX: Better solutions welcome, but this seems cheap enough.
        (delete-consecutive-dups files)))
     (`Hg
-     (let ((default-directory (expand-file-name (file-name-as-directory dir)))
-           (args (list (concat "-mcard" (and project-vc-include-untracked "u"))
-                       "--no-status"
-                       "-0")))
+     (let* ((default-directory (expand-file-name (file-name-as-directory dir)))
+            (include-untracked (project--value-in-dir
+                                'project-vc-include-untracked
+                                dir))
+            (args (list (concat "-mcard" (and include-untracked "u"))
+                        "--no-status"
+                        "-0")))
        (when extra-ignores
          (setq args (nconc args
                            (mapcan
@@ -681,6 +689,11 @@ project backend implementation of 
`project-external-roots'.")
           (lambda (s) (concat default-directory s))
           (split-string (buffer-string) "\0" t)))))))
 
+(defun project--vc-merge-submodules-p (dir)
+  (project--value-in-dir
+   'project-vc-merge-submodules
+   dir))
+
 (defun project--git-submodules ()
   ;; 'git submodule foreach' is much slower.
   (condition-case nil
@@ -722,7 +735,7 @@ project backend implementation of 
`project-external-roots'.")
          (condition-case nil
              (vc-call-backend backend 'ignore-completion-table root)
            (vc-not-supported () nil)))))
-     project-vc-ignores
+     (project--value-in-dir 'project-vc-ignores root)
      (mapcar
       (lambda (dir)
         (concat dir "/"))
@@ -753,9 +766,16 @@ DIRS must contain directory names."
   ;; Sidestep the issue of expanded/abbreviated file names here.
   (cl-set-difference files dirs :test #'file-in-directory-p))
 
+(defun project--value-in-dir (var dir)
+  (with-temp-buffer
+    (setq default-directory dir)
+    (let ((enable-local-variables :all))
+      (hack-dir-local-variables-non-file-buffer))
+    (symbol-value var)))
+
 (cl-defmethod project-buffers ((project (head vc)))
   (let* ((root (expand-file-name (file-name-as-directory (project-root 
project))))
-         (modules (unless (or project-vc-merge-submodules
+         (modules (unless (or (project--vc-merge-submodules-p root)
                               (project--submodule-p root))
                     (mapcar
                      (lambda (m) (format "%s%s/" root m))
@@ -1019,7 +1039,14 @@ by the user at will."
          (_ (when included-cpd
               (setq substrings (cons "./" substrings))))
          (new-collection (project--file-completion-table substrings))
-         (relname (let ((history-add-new-input nil))
+         (abbr-cpd (abbreviate-file-name common-parent-directory))
+         (relname (cl-letf ((history-add-new-input nil)
+                            ((symbol-value hist)
+                             (mapcan
+                              (lambda (s)
+                                (and (string-prefix-p abbr-cpd s)
+                                     (list (substring s (length abbr-cpd)))))
+                              (symbol-value hist))))
                     (project--completing-read-strict prompt
                                                      new-collection
                                                      predicate
@@ -1321,18 +1348,33 @@ By default, all project buffers are listed except those 
whose names
 start with a space (which are for internal use).  With prefix argument
 ARG, show only buffers that are visiting files."
   (interactive "P")
-  (let ((pr (project-current t)))
+  (let* ((pr (project-current t))
+         (buffer-list-function
+          (lambda ()
+            (seq-filter
+             (lambda (buffer)
+               (let ((name (buffer-name buffer))
+                     (file (buffer-file-name buffer)))
+                 (and (or (not (string= (substring name 0 1) " "))
+                          file)
+                      (not (eq buffer (current-buffer)))
+                      (or file (not Buffer-menu-files-only)))))
+             (project-buffers pr)))))
     (display-buffer
      (if (version< emacs-version "29.0.50")
-         (let ((buf (list-buffers-noselect arg (project-buffers pr))))
+         (let ((buf (list-buffers-noselect
+                     arg (with-current-buffer
+                             (get-buffer-create "*Buffer List*")
+                           (let ((Buffer-menu-files-only arg))
+                             (funcall buffer-list-function))))))
            (with-current-buffer buf
              (setq-local revert-buffer-function
                          (lambda (&rest _ignored)
-                           (list-buffers--refresh (project-buffers pr))
+                           (list-buffers--refresh
+                            (funcall buffer-list-function))
                            (tabulated-list-print t))))
            buf)
-       (list-buffers-noselect
-        arg nil (lambda (buf) (memq buf (project-buffers pr))))))))
+       (list-buffers-noselect arg buffer-list-function)))))
 
 (defcustom project-kill-buffer-conditions
   '(buffer-file-name    ; All file-visiting buffers are included.
diff --git a/lisp/progmodes/python.el b/lisp/progmodes/python.el
index ebee703499..bdc9e6fa78 100644
--- a/lisp/progmodes/python.el
+++ b/lisp/progmodes/python.el
@@ -993,7 +993,8 @@ It makes underscores and dots word constituent chars.")
 
 (defvar python--treesit-operators
   '("-" "-=" "!=" "*" "**" "**=" "*=" "/" "//" "//=" "/=" "&" "%" "%="
-    "^" "+" "+=" "<" "<<" "<=" "<>" "=" "==" ">" ">=" ">>" "|" "~" "@" "@="))
+    "^" "+" "->" "+=" "<" "<<" "<=" "<>" "=" ":=" "==" ">" ">=" ">>" "|"
+    "~" "@" "@="))
 
 (defvar python--treesit-special-attributes
   '("__annotations__" "__closure__" "__code__"
@@ -1094,6 +1095,14 @@ fontified."
      (class_definition
       name: (identifier) @font-lock-type-face))
 
+   :feature 'function
+   :language 'python
+   '((function_definition
+      name: (identifier) @font-lock-function-name-face)
+     (call function: (identifier) @font-lock-function-name-face)
+     (call function: (attribute
+                      attribute: (identifier) @font-lock-function-name-face)))
+
    :feature 'keyword
    :language 'python
    `([,@python--treesit-keywords] @font-lock-keyword-face
@@ -6563,19 +6572,21 @@ implementations: `python-mode' and `python-ts-mode'."
         (add-function :before-until (local 'eldoc-documentation-function)
                       #'python-eldoc-function))))
 
-  (add-to-list
-   'hs-special-modes-alist
-   `(python-mode
-     ,python-nav-beginning-of-block-regexp
-     ;; Use the empty string as end regexp so it doesn't default to
-     ;; "\\s)".  This way parens at end of defun are properly hidden.
-     ""
-     "#"
-     python-hideshow-forward-sexp-function
-     nil
-     python-nav-beginning-of-block
-     python-hideshow-find-next-block
-     python-info-looking-at-beginning-of-block))
+  ;; TODO: Use tree-sitter to figure out the block in `python-ts-mode'.
+  (dolist (mode '(python-mode python-ts-mode))
+    (add-to-list
+     'hs-special-modes-alist
+     `(,mode
+       ,python-nav-beginning-of-block-regexp
+       ;; Use the empty string as end regexp so it doesn't default to
+       ;; "\\s)".  This way parens at end of defun are properly hidden.
+       ""
+       "#"
+       python-hideshow-forward-sexp-function
+       nil
+       python-nav-beginning-of-block
+       python-hideshow-find-next-block
+       python-info-looking-at-beginning-of-block)))
 
   (setq-local outline-regexp (python-rx (* space) block-start))
   (setq-local outline-level
@@ -6618,6 +6629,7 @@ implementations: `python-mode' and `python-ts-mode'."
   "Major mode for editing Python files, using tree-sitter library.
 
 \\{python-ts-mode-map}"
+  :syntax-table python-mode-syntax-table
   (when (treesit-ready-p 'python)
     (treesit-parser-create 'python)
     (setq-local treesit-font-lock-feature-list
@@ -6625,7 +6637,7 @@ implementations: `python-mode' and `python-ts-mode'."
                   ( keyword string type)
                   ( assignment builtin constant decorator
                     escape-sequence number property string-interpolation )
-                  ( bracket delimiter operator)))
+                  ( function bracket delimiter operator)))
     (setq-local treesit-font-lock-settings python--treesit-settings)
     (setq-local imenu-create-index-function
                 #'python-imenu-treesit-create-index)
@@ -6633,8 +6645,8 @@ implementations: `python-mode' and `python-ts-mode'."
                                               "_definition"))
     (treesit-major-mode-setup)
 
-  (when python-indent-guess-indent-offset
-    (python-indent-guess-indent-offset))))
+    (when python-indent-guess-indent-offset
+      (python-indent-guess-indent-offset))))
 
 ;;; Completion predicates for M-x
 ;; Commands that only make sense when editing Python code
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 17467b5554..fa51597697 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -134,6 +134,13 @@ This should only be called after matching against 
`ruby-here-doc-beg-re'."
 (defconst ruby-symbol-re (concat "[" ruby-symbol-chars "]")
   "Regexp to match symbols.")
 
+(defconst ruby-endless-method-head-re
+  (format " *\\(%s+\\.\\)?%s+[?!]? *\\(([^()]*)\\)? +="
+          ruby-symbol-re ruby-symbol-re)
+  "Regexp to match the beginning of an endless method definition.
+
+It should match the part after \"def\" and until \"=\".")
+
 (defvar ruby-use-smie t)
 (make-obsolete-variable 'ruby-use-smie nil "28.1")
 
@@ -351,7 +358,8 @@ This only affects the output of the command 
`ruby-toggle-block'."
        (exp  (exp1) (exp "," exp) (exp "=" exp)
              (id " @ " exp))
        (exp1 (exp2) (exp2 "?" exp1 ":" exp1))
-       (exp2 (exp3) (exp3 "." exp3))
+       (exp2 (exp3) (exp3 "." exp3)
+             (exp3 "def=" exp3))
        (exp3 ("def" insts "end")
              ("begin" insts-rescue-insts "end")
              ("do" insts "end")
@@ -468,7 +476,7 @@ This only affects the output of the command 
`ruby-toggle-block'."
                                              "else" "elsif" "do" "end" "and")
                                            'symbols))))
          (memq (car (syntax-after pos)) '(7 15))
-         (looking-at "[([]\\|[-+!~:]\\(?:\\sw\\|\\s_\\)")))))
+         (looking-at "[([]\\|[-+!~:@$]\\(?:\\sw\\|\\s_\\)")))))
 
 (defun ruby-smie--before-method-name ()
   ;; Only need to be accurate when method has keyword name.
@@ -528,6 +536,9 @@ This only affects the output of the command 
`ruby-toggle-block'."
               (ruby-smie--forward-token)) ;Fully redundant.
              (t ";")))
            ((equal tok "&.") ".")
+           ((and (equal tok "def")
+                 (looking-at ruby-endless-method-head-re))
+            "def=")
            (t tok)))))))))
 
 (defun ruby-smie--backward-token ()
@@ -575,6 +586,9 @@ This only affects the output of the command 
`ruby-toggle-block'."
             (ruby-smie--backward-token)) ;Fully redundant.
            (t ";")))
          ((equal tok "&.") ".")
+         ((and (equal tok "def")
+               (looking-at (concat "def" ruby-endless-method-head-re)))
+          "def=")
          (t tok)))))))
 
 (defun ruby-smie--indent-to-stmt ()
@@ -629,6 +643,11 @@ This only affects the output of the command 
`ruby-toggle-block'."
                      (not (ruby-smie--bosp)))
            (forward-char -1))
          (smie-indent-virtual))
+        ((save-excursion
+           (and (smie-rule-parent-p " @ ")
+                (goto-char (nth 1 (smie-indent--parent)))
+                (smie-rule-prev-p "def=")
+                (cons 'column (- (current-column) 3)))))
         (t (smie-rule-parent))))))
     (`(:after . ,(or "(" "[" "{"))
      ;; FIXME: Shouldn't this be the default behavior of
@@ -672,6 +691,12 @@ This only affects the output of the command 
`ruby-toggle-block'."
      (and (smie-rule-parent-p ";" nil)
           (smie-indent--hanging-p)
           ruby-indent-level))
+    (`(:before . "=")
+     (save-excursion
+      (and (smie-rule-parent-p " @ ")
+           (goto-char (nth 1 (smie-indent--parent)))
+           (smie-rule-prev-p "def=")
+           (cons 'column (+ (current-column) ruby-indent-level -3)))))
     (`(:after . ,(or "?" ":")) ruby-indent-level)
     (`(:before . ,(guard (memq (intern-soft token) ruby-alignable-keywords)))
      (when (not (ruby--at-indentation-p))
@@ -1375,9 +1400,10 @@ With ARG, move backward multiple defuns.  Negative ARG 
means
 move forward."
   (interactive "p")
   (let (case-fold-search)
-    (and (re-search-backward (concat "^\\s *" ruby-defun-beg-re "\\_>")
-                             nil t (or arg 1))
-         (beginning-of-line))))
+    (when (re-search-backward (concat "^\\s *" ruby-defun-beg-re "\\_>")
+                              nil t (or arg 1))
+      (beginning-of-line)
+      t)))
 
 (defun ruby-end-of-defun ()
   "Move point to the end of the current defun.
@@ -1611,7 +1637,8 @@ For example:
 See `add-log-current-defun-function'."
   (condition-case nil
       (save-excursion
-        (let* ((indent 0) mname mlist
+        (let* ((indent (ruby--add-log-current-indent))
+               mname mlist
                (start (point))
                (make-definition-re
                 (lambda (re &optional method-name?)
@@ -1626,18 +1653,30 @@ See `add-log-current-defun-function'."
                (definition-re (funcall make-definition-re ruby-defun-beg-re t))
                (module-re (funcall make-definition-re "\\(class\\|module\\)")))
           ;; Get the current method definition (or class/module).
-          (when (re-search-backward definition-re nil t)
+          (when (catch 'found
+                  (while (and (re-search-backward definition-re nil t)
+                              (if (if (string-equal "def" (match-string 1))
+                                      ;; We're inside a method.
+                                      (if (ruby-block-contains-point (1- 
start))
+                                          t
+                                        ;; Try to match a method only once.
+                                        (setq definition-re module-re)
+                                        nil)
+                                    ;; Class/module. For performance,
+                                    ;; comparing indentation.
+                                    (or (not (numberp indent))
+                                        (> indent (current-indentation))))
+                                  (throw 'found t)
+                                t))))
             (goto-char (match-beginning 1))
             (if (not (string-equal "def" (match-string 1)))
                 (setq mlist (list (match-string 2)))
-              ;; We're inside the method. For classes and modules,
-              ;; this check is skipped for performance.
-              (when (ruby-block-contains-point start)
-                (setq mname (match-string 2))))
+              (setq mname (match-string 2)))
             (setq indent (current-column))
             (beginning-of-line))
           ;; Walk up the class/module nesting.
-          (while (and (> indent 0)
+          (while (and indent
+                      (> indent 0)
                       (re-search-backward module-re nil t))
             (goto-char (match-beginning 1))
             (when (< (current-column) indent)
@@ -1691,6 +1730,17 @@ See `add-log-current-defun-function'."
         (ruby-forward-sexp))
       (> (point) pt))))
 
+(defun ruby--add-log-current-indent ()
+  (save-excursion
+    (back-to-indentation)
+    (cond
+     ((looking-at "[[:graph:]]")
+      (current-indentation))
+     (ruby-use-smie
+      (smie-indent-calculate))
+     (t
+      (ruby-calculate-indent)))))
+
 (defun ruby-brace-to-do-end (orig end)
   (let (beg-marker end-marker)
     (goto-char end)
diff --git a/lisp/progmodes/rust-ts-mode.el b/lisp/progmodes/rust-ts-mode.el
new file mode 100644
index 0000000000..8b2ed19101
--- /dev/null
+++ b/lisp/progmodes/rust-ts-mode.el
@@ -0,0 +1,371 @@
+;;; rust-ts-mode.el --- tree-sitter support for Rust  -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author     : Randy Taylor <dev@rjt.dev>
+;; Maintainer : Randy Taylor <dev@rjt.dev>
+;; Created    : December 2022
+;; Keywords   : rust languages tree-sitter
+
+;; 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:
+;;
+
+;;; Code:
+
+(require 'treesit)
+(eval-when-compile (require 'rx))
+
+(declare-function treesit-parser-create "treesit.c")
+(declare-function treesit-induce-sparse-tree "treesit.c")
+(declare-function treesit-node-child "treesit.c")
+(declare-function treesit-node-child-by-field-name "treesit.c")
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-type "treesit.c")
+
+(defcustom rust-ts-mode-indent-offset 4
+  "Number of spaces for each indentation step in `rust-ts-mode'."
+  :version "29.1"
+  :type 'integer
+  :safe 'integerp
+  :group 'rust)
+
+(defvar rust-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?+   "."      table)
+    (modify-syntax-entry ?-   "."      table)
+    (modify-syntax-entry ?=   "."      table)
+    (modify-syntax-entry ?%   "."      table)
+    (modify-syntax-entry ?&   "."      table)
+    (modify-syntax-entry ?|   "."      table)
+    (modify-syntax-entry ?^   "."      table)
+    (modify-syntax-entry ?!   "."      table)
+    (modify-syntax-entry ?@   "."      table)
+    (modify-syntax-entry ?~   "."      table)
+    (modify-syntax-entry ?<   "."      table)
+    (modify-syntax-entry ?>   "."      table)
+    (modify-syntax-entry ?/   ". 124b" table)
+    (modify-syntax-entry ?*   ". 23"   table)
+    (modify-syntax-entry ?\n  "> b"    table)
+    (modify-syntax-entry ?\^m "> b"    table)
+    table)
+  "Syntax table for `rust-ts-mode'.")
+
+(defvar rust-ts-mode--indent-rules
+  `((rust
+     ((node-is ")") parent-bol 0)
+     ((node-is "]") parent-bol 0)
+     ((node-is "}") (and parent parent-bol) 0)
+     ((parent-is "arguments") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "await_expression") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "array_expression") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "binary_expression") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "block") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "declaration_list") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "enum_variant_list") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "field_declaration_list") parent-bol 
rust-ts-mode-indent-offset)
+     ((parent-is "field_expression") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "field_initializer_list") parent-bol 
rust-ts-mode-indent-offset)
+     ((parent-is "let_declaration") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "macro_definition") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "parameters") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "token_tree") parent-bol rust-ts-mode-indent-offset)
+     ((parent-is "use_list") parent-bol rust-ts-mode-indent-offset)))
+  "Tree-sitter indent rules for `rust-ts-mode'.")
+
+(defvar rust-ts-mode--builtin-macros
+  '("concat_bytes" "concat_idents" "const_format_args"
+    "format_args_nl" "log_syntax" "trace_macros" "assert" "assert_eq"
+    "assert_ne" "cfg" "column" "compile_error" "concat" "dbg"
+    "debug_assert" "debug_assert_eq" "debug_assert_ne" "env" "eprint"
+    "eprintln" "file" "format" "format_args" "include" "include_bytes"
+    "include_str" "is_x86_feature_detected" "line" "matches"
+    "module_path" "option_env" "panic" "print" "println" "stringify"
+    "thread_local" "todo" "try" "unimplemented" "unreachable" "vec"
+    "write" "writeln")
+  "Rust built-in macros for tree-sitter font-locking.")
+
+(defvar rust-ts-mode--keywords
+  '("as" "async" "await" "break" "const" "continue" "dyn" "else"
+    "enum" "extern" "fn" "for" "if" "impl" "in" "let" "loop" "match"
+    "mod" "move" "pub" "ref" "return" "static" "struct" "trait" "type"
+    "union" "unsafe" "use" "where" "while" (crate) (self) (super)
+    (mutable_specifier))
+  "Rust keywords for tree-sitter font-locking.")
+
+(defvar rust-ts-mode--operators
+  '("!"  "!=" "%" "%=" "&" "&=" "&&" "*" "*=" "+" "+=" "," "-" "-="
+    "->" "."  ".."  "..=" "..."  "/" "/=" ":" ";" "<<" "<<=" "<" "<="
+    "=" "==" "=>" ">" ">=" ">>" ">>=" "@" "^" "^=" "|" "|=" "||" "?")
+  "Rust operators for tree-sitter font-locking.")
+
+(defvar rust-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'rust
+   :feature 'attribute
+   '((attribute_item) @font-lock-constant-face
+     (inner_attribute_item) @font-lock-constant-face)
+
+   :language 'rust
+   :feature 'bracket
+   '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
+
+   :language 'rust
+   :feature 'builtin
+   `((macro_invocation
+      macro: ((identifier) @font-lock-builtin-face
+              (:match ,(rx-to-string
+                        `(seq bol
+                              (or ,@rust-ts-mode--builtin-macros)
+                              eol))
+                      @font-lock-builtin-face)))
+     ((identifier) @font-lock-type-face
+      (:match "^\\(:?Err\\|Ok\\|None\\|Some\\)$" @font-lock-type-face)))
+
+   :language 'rust
+   :feature 'comment
+   '(([(block_comment) (line_comment)]) @font-lock-comment-face)
+
+   :language 'rust
+   :feature 'constant
+   `((boolean_literal) @font-lock-constant-face
+     ((identifier) @font-lock-constant-face
+      (:match "^[A-Z][A-Z\\d_]*$" @font-lock-constant-face)))
+
+   :language 'rust
+   :feature 'delimiter
+   '((["," "." ";" ":" "::"]) @font-lock-delimiter-face)
+
+   :language 'rust
+   :feature 'function
+   '((call_expression
+      function:
+      [(identifier) @font-lock-function-name-face
+       (field_expression
+        field: (field_identifier) @font-lock-function-name-face)
+       (scoped_identifier
+        name: (identifier) @font-lock-function-name-face)])
+     (function_item (identifier) @font-lock-function-name-face)
+     (generic_function
+      function: [(identifier) @font-lock-function-name-face
+                 (field_expression
+                  field: (field_identifier) @font-lock-function-name-face)
+                 (scoped_identifier
+                  name: (identifier) @font-lock-function-name-face)])
+     (macro_definition "macro_rules!" @font-lock-constant-face)
+     (macro_definition (identifier) @font-lock-preprocessor-face)
+     (macro_invocation macro: (identifier) @font-lock-preprocessor-face))
+
+   :language 'rust
+   :feature 'keyword
+   `([,@rust-ts-mode--keywords] @font-lock-keyword-face)
+
+   :language 'rust
+   :feature 'number
+   '([(float_literal) (integer_literal)] @font-lock-number-face)
+
+   :language 'rust
+   :feature 'operator
+   `([,@rust-ts-mode--operators] @font-lock-operator-face)
+
+   :language 'rust
+   :feature 'string
+   '([(char_literal)
+      (raw_string_literal)
+      (string_literal)] @font-lock-string-face)
+
+   :language 'rust
+   :feature 'type
+   `((call_expression
+      function: (scoped_identifier
+                 path: (identifier) @font-lock-type-face))
+     (enum_variant name: (identifier) @font-lock-type-face)
+     (match_arm
+      pattern: (match_pattern (_ type: (identifier) @font-lock-type-face)))
+     (match_arm
+      pattern: (match_pattern
+                (_ type: (scoped_identifier
+                          path: (identifier) @font-lock-type-face))))
+     (mod_item name: (identifier) @font-lock-constant-face)
+     (primitive_type) @font-lock-type-face
+     (type_identifier) @font-lock-type-face
+     (scoped_identifier name: (identifier) @font-lock-type-face)
+     (scoped_identifier path: (identifier) @font-lock-constant-face)
+     (scoped_identifier
+      (scoped_identifier
+       path: (identifier) @font-lock-constant-face))
+     ((scoped_identifier
+       path: [(identifier) @font-lock-type-face
+              (scoped_identifier
+               name: (identifier) @font-lock-type-face)])
+      (:match "^[A-Z]" @font-lock-type-face))
+     (scoped_type_identifier path: (identifier) @font-lock-constant-face)
+     (scoped_use_list
+      path: [(identifier) @font-lock-constant-face
+             (scoped_identifier (identifier) @font-lock-constant-face)])
+     (type_identifier) @font-lock-type-face
+     (use_as_clause alias: (identifier) @font-lock-type-face)
+     (use_list (identifier) @font-lock-type-face))
+
+   :language 'rust
+   :feature 'variable
+   '((identifier) @font-lock-variable-name-face
+     ;; Everything in a token_tree is an identifier.
+     (token_tree (identifier) @default))
+
+   :language 'rust
+   :feature 'escape-sequence
+   :override t
+   '((escape_sequence) @font-lock-escape-face)
+
+   :language 'rust
+   :feature 'property
+   :override t
+   '((field_identifier) @font-lock-property-face
+     (shorthand_field_initializer (identifier) @font-lock-property-face))
+
+   :language 'rust
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Tree-sitter font-lock settings for `rust-ts-mode'.")
+
+(defun rust-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (enum-tree (treesit-induce-sparse-tree
+                     node "enum_item" nil))
+         (enum-index (rust-ts-mode--imenu-1 enum-tree))
+         (func-tree (treesit-induce-sparse-tree
+                     node "function_item" nil))
+         (func-index (rust-ts-mode--imenu-1 func-tree))
+         (impl-tree (treesit-induce-sparse-tree
+                     node "impl_item" nil))
+         (impl-index (rust-ts-mode--imenu-1 impl-tree))
+         (mod-tree (treesit-induce-sparse-tree
+                    node "mod_item" nil))
+         (mod-index (rust-ts-mode--imenu-1 mod-tree))
+         (struct-tree (treesit-induce-sparse-tree
+                       node "struct_item" nil))
+         (struct-index (rust-ts-mode--imenu-1 struct-tree))
+         (type-tree (treesit-induce-sparse-tree
+                     node "type_item" nil))
+         (type-index (rust-ts-mode--imenu-1 type-tree)))
+    (append
+     (when mod-index `(("Module" . ,mod-index)))
+     (when enum-index `(("Enum" . ,enum-index)))
+     (when impl-index `(("Impl" . ,impl-index)))
+     (when type-index `(("Type" . ,type-index)))
+     (when struct-index `(("Struct" . ,struct-index)))
+     (when func-index `(("Fn" . ,func-index))))))
+
+(defun rust-ts-mode--imenu-1 (node)
+  "Helper for `rust-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (children (cdr node))
+         (subtrees (mapcan #'rust-ts-mode--imenu-1
+                           children))
+         (name (when ts-node
+                 (pcase (treesit-node-type ts-node)
+                   ("enum_item"
+                    (treesit-node-text
+                     (treesit-node-child-by-field-name ts-node "name") t))
+                   ("function_item"
+                    (treesit-node-text
+                     (treesit-node-child-by-field-name ts-node "name") t))
+                   ("impl_item"
+                    (let ((trait-node (treesit-node-child-by-field-name 
ts-node "trait")))
+                      (concat
+                       (treesit-node-text
+                        trait-node t)
+                       (when trait-node
+                         " for ")
+                       (treesit-node-text
+                        (treesit-node-child-by-field-name ts-node "type") t))))
+                   ("mod_item"
+                    (treesit-node-text
+                     (treesit-node-child-by-field-name ts-node "name") t))
+                   ("struct_item"
+                    (treesit-node-text
+                     (treesit-node-child-by-field-name ts-node "name") t))
+                   ("type_item"
+                    (treesit-node-text
+                     (treesit-node-child-by-field-name ts-node "name") t)))))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((or (null ts-node) (null name)) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
+
+;;;###autoload
+(define-derived-mode rust-ts-mode prog-mode "Rust"
+  "Major mode for editing Rust, powered by tree-sitter."
+  :group 'rust
+  :syntax-table rust-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'rust)
+    (treesit-parser-create 'rust)
+
+    ;; Comments.
+    (setq-local comment-start "// ")
+    (setq-local comment-end "")
+    (setq-local comment-start-skip (rx (or (seq "/" (+ "/"))
+                                           (seq "/" (+ "*")))
+                                       (* (syntax whitespace))))
+    (setq-local comment-end-skip
+                (rx (* (syntax whitespace))
+                    (group (or (syntax comment-end)
+                               (seq (+ "*") "/")))))
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings rust-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '(( comment)
+                  ( keyword string)
+                  ( attribute builtin constant escape-sequence
+                    function number property type variable)
+                  ( bracket delimiter error operator)))
+
+    ;; Imenu.
+    (setq-local imenu-create-index-function #'rust-ts-mode--imenu)
+    (setq-local which-func-functions nil)
+
+    ;; Indent.
+    (setq-local indent-tabs-mode nil
+                treesit-simple-indent-rules rust-ts-mode--indent-rules)
+
+    ;; Navigation.
+    (setq-local treesit-defun-type-regexp
+                (regexp-opt '("enum_item"
+                              "function_item"
+                              "impl_item"
+                              "struct_item")))
+
+    (treesit-major-mode-setup)))
+
+(provide 'rust-ts-mode)
+
+;;; rust-ts-mode.el ends here
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el
index e170d18afe..3f995d17b5 100644
--- a/lisp/progmodes/sh-script.el
+++ b/lisp/progmodes/sh-script.el
@@ -1611,7 +1611,9 @@ with your script for an edit-interpret-debug cycle."
   "Major mode for editing Bash shell scripts.
 This mode automatically falls back to `sh-mode' if the buffer is
 not written in Bash or sh."
+  :syntax-table sh-mode-syntax-table
   (when (treesit-ready-p 'bash)
+    (treesit-parser-create 'bash)
     (setq-local treesit-font-lock-feature-list
                 '(( comment function)
                   ( command declaration-command keyword string)
@@ -1619,6 +1621,11 @@ not written in Bash or sh."
                   ( bracket delimiter misc-punctuation operator)))
     (setq-local treesit-font-lock-settings
                 sh-mode--treesit-settings)
+    (setq-local treesit-text-type-regexp
+                (regexp-opt '("comment"
+                              "heredoc_start"
+                              "heredoc_body")))
+    (setq-local treesit-defun-type-regexp "function_definition")
     (treesit-major-mode-setup)))
 
 (advice-add 'bash-ts-mode :around #'sh--redirect-bash-ts-mode
diff --git a/lisp/progmodes/sql.el b/lisp/progmodes/sql.el
index e585799dc6..6a71da77a2 100644
--- a/lisp/progmodes/sql.el
+++ b/lisp/progmodes/sql.el
@@ -4526,7 +4526,8 @@ optionally is saved to the user's init file."
   "Run PRODUCT interpreter as an inferior process.
 
 If buffer `*SQL*' exists but no process is running, make a new process.
-If buffer exists and a process is running, just switch to buffer `*SQL*'.
+If buffer exists and a process is running, just make sure buffer `*SQL*'
+is displayed.
 
 To specify the SQL product, prefix the call with
 \\[universal-argument].  To set the buffer name as well, prefix
diff --git a/lisp/progmodes/typescript-ts-mode.el 
b/lisp/progmodes/typescript-ts-mode.el
index 48ac1169fe..6ba1b9b12c 100644
--- a/lisp/progmodes/typescript-ts-mode.el
+++ b/lisp/progmodes/typescript-ts-mode.el
@@ -9,19 +9,18 @@
 
 ;; This file is part of GNU Emacs.
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <http://www.gnu.org/licenses/>.
-
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 ;;
@@ -45,7 +44,6 @@
   (let ((table (make-syntax-table)))
     ;; Taken from the cc-langs version
     (modify-syntax-entry ?_  "_"     table)
-    (modify-syntax-entry ?$ "_"      table)
     (modify-syntax-entry ?\\ "\\"    table)
     (modify-syntax-entry ?+  "."     table)
     (modify-syntax-entry ?-  "."     table)
@@ -55,8 +53,14 @@
     (modify-syntax-entry ?>  "."     table)
     (modify-syntax-entry ?&  "."     table)
     (modify-syntax-entry ?|  "."     table)
-    (modify-syntax-entry ?` "\""     table)
+    (modify-syntax-entry ?\' "\""    table)
     (modify-syntax-entry ?\240 "."   table)
+    (modify-syntax-entry ?/  ". 124b" table)
+    (modify-syntax-entry ?*  ". 23"   table)
+    (modify-syntax-entry ?\n "> b"  table)
+    (modify-syntax-entry ?\^m "> b" table)
+    (modify-syntax-entry ?$ "_" table)
+    (modify-syntax-entry ?` "\"" table)
     table)
   "Syntax table for `typescript-ts-mode'.")
 
@@ -85,15 +89,19 @@ Argument LANGUAGE is either `typescript' or `tsx'."
      ((parent-is "object") parent-bol typescript-ts-mode-indent-offset)
      ((parent-is "object_type") parent-bol typescript-ts-mode-indent-offset)
      ((parent-is "enum_body") parent-bol typescript-ts-mode-indent-offset)
+     ((parent-is "class_body") parent-bol typescript-ts-mode-indent-offset)
      ((parent-is "arrow_function") parent-bol typescript-ts-mode-indent-offset)
      ((parent-is "parenthesized_expression") parent-bol 
typescript-ts-mode-indent-offset)
+     ((parent-is "binary_expression") parent-bol 
typescript-ts-mode-indent-offset)
 
      ,@(when (eq language 'tsx)
-         `(((parent-is "jsx_opening_element") parent 
typescript-ts-mode-indent-offset)
+         `(((node-is "jsx_fragment") parent typescript-ts-mode-indent-offset)
+           ((node-is "jsx_element") parent typescript-ts-mode-indent-offset)
+           ((node-is "jsx_expression") parent typescript-ts-mode-indent-offset)
+           ((node-is "jsx_self_closing_element") parent 
typescript-ts-mode-indent-offset)
            ((node-is "jsx_closing_element") parent 0)
-           ((parent-is "jsx_element") parent typescript-ts-mode-indent-offset)
            ((node-is "/") parent 0)
-           ((parent-is "jsx_self_closing_element") parent 
typescript-ts-mode-indent-offset)))
+           ((node-is ">") parent 0)))
      (no-node parent-bol 0))))
 
 (defvar typescript-ts-mode--keywords
@@ -213,7 +221,38 @@ Argument LANGUAGE is either `typescript' or `tsx'."
       parameters:
       [(_ (identifier) @font-lock-variable-name-face)
        (_ (_ (identifier) @font-lock-variable-name-face))
-       (_ (_ (_ (identifier) @font-lock-variable-name-face)))]))
+       (_ (_ (_ (identifier) @font-lock-variable-name-face)))])
+
+     (return_statement (identifier) @font-lock-variable-name-face)
+
+     (binary_expression left: (identifier) @font-lock-variable-name-face)
+     (binary_expression right: (identifier) @font-lock-variable-name-face)
+
+     (arguments (identifier) @font-lock-variable-name-face)
+
+     (parenthesized_expression (identifier) @font-lock-variable-name-face)
+     (parenthesized_expression (_ (identifier) @font-lock-variable-name-face)))
+
+   :language language
+   :override t
+   :feature 'property
+   `((property_signature
+      name: (property_identifier) @font-lock-property-face)
+     (public_field_definition
+      name: (property_identifier) @font-lock-property-face)
+     (member_expression
+      object: (identifier) @font-lock-variable-name-face)
+     (member_expression
+      property: (_) @font-lock-property-face)
+
+     (pair key: (property_identifier) @font-lock-variable-name-face)
+
+     (pair value: (identifier) @font-lock-variable-name-face)
+
+     ((shorthand_property_identifier) @font-lock-property-face)
+
+     ((shorthand_property_identifier_pattern)
+      @font-lock-property-face))
 
    :language language
    :override t
@@ -277,17 +316,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
    :language language
    :feature 'escape-sequence
    :override t
-   '((escape_sequence) @font-lock-escape-face)
-
-   :language language
-   :override t
-   :feature 'property
-   `((pair value: (identifier) @font-lock-variable-name-face)
-
-     ((shorthand_property_identifier) @font-lock-property-face)
-
-     ((shorthand_property_identifier_pattern)
-      @font-lock-property-face))))
+   '((escape_sequence) @font-lock-escape-face)))
 
 ;;;###autoload
 (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-ts-mode))
@@ -310,6 +339,11 @@ Argument LANGUAGE is either `typescript' or `tsx'."
                   (group (or (syntax comment-end)
                              (seq (+ "*") "/")))))
 
+  (setq-local treesit-text-type-regexp
+              (regexp-opt '("comment"
+                            "template_string")))
+  (setq-local treesit-defun-prefer-top-level t)
+
   ;; Electric
   (setq-local electric-indent-chars
               (append "{}():;," electric-indent-chars))
@@ -343,8 +377,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
     (setq-local treesit-font-lock-settings
                 (typescript-ts-mode--font-lock-settings 'typescript))
     (setq-local treesit-font-lock-feature-list
-                '((comment declaration)
-                  (keyword string)
+                '((comment declaration keyword string escape-sequence)
                   (constant expression identifier number pattern property)
                   (bracket delimiter)))
 
@@ -378,8 +411,7 @@ Argument LANGUAGE is either `typescript' or `tsx'."
     (setq-local treesit-font-lock-settings
                 (typescript-ts-mode--font-lock-settings 'tsx))
     (setq-local treesit-font-lock-feature-list
-                '((comment declaration)
-                  (keyword string)
+                '((comment declaration keyword string escape-sequence)
                   (constant expression identifier jsx number pattern property)
                   (bracket delimiter)))
 
diff --git a/lisp/progmodes/verilog-mode.el b/lisp/progmodes/verilog-mode.el
index e5458e6a07..47a1cb3233 100644
--- a/lisp/progmodes/verilog-mode.el
+++ b/lisp/progmodes/verilog-mode.el
@@ -9,7 +9,7 @@
 ;; Keywords: languages
 ;; The "Version" is the date followed by the decimal rendition of the Git
 ;;     commit hex.
-;; Version: 2021.10.14.127365406
+;; Version: 2022.12.18.181110314
 
 ;; Yoni Rabkin <yoni@rabkins.net> contacted the maintainer of this
 ;; file on 19/3/2008, and the maintainer agreed that when a bug is
@@ -124,7 +124,7 @@
 ;;
 
 ;; This variable will always hold the version number of the mode
-(defconst verilog-mode-version "2021-10-14-797711e-vpo-GNU"
+(defconst verilog-mode-version "2022-12-18-acb862a-vpo-GNU"
   "Version of this Verilog mode.")
 (defconst verilog-mode-release-emacs t
   "If non-nil, this version of Verilog mode was released with Emacs itself.")
@@ -455,11 +455,11 @@ This function may be removed when Emacs 21 is no longer 
supported."
            last-command-event)))
 
 (defvar verilog-no-change-functions nil
-  "True if `after-change-functions' is disabled.
+  "Non-nil if `after-change-functions' is disabled.
 Use of `syntax-ppss' may break, as ppss's cache may get corrupted.")
 
 (defvar verilog-in-hooks nil
-  "True when within a `verilog-run-hooks' block.")
+  "Non-nil when within a `verilog-run-hooks' block.")
 
 (defmacro verilog-run-hooks (&rest hooks)
   "Run each hook in HOOKS using `run-hooks'.
@@ -505,8 +505,14 @@ Set `verilog-in-hooks' during this time, to assist AUTO 
caches."
 (defvar verilog-debug nil
   "Non-nil means enable debug messages for `verilog-mode' internals.")
 
-(defvar verilog-warn-fatal nil
-  "Non-nil means `verilog-warn-error' warnings are fatal `error's.")
+(defcustom verilog-warn-fatal nil
+  "Non-nil means `verilog-warn-error' warnings are fatal `error's."
+  :group 'verilog-mode-auto
+  :type 'boolean)
+(put 'verilog-warn-fatal 'safe-local-variable #'verilog-booleanp)
+
+;; Internal use similar to `verilog-warn-fatal'
+(defvar verilog-warn-fatal-internal t)
 
 (defcustom verilog-linter
   "echo 'No verilog-linter set, see \"M-x describe-variable verilog-linter\"'"
@@ -679,6 +685,18 @@ Set to 0 to have all directives start at the left side of 
the screen."
   :type 'integer)
 (put 'verilog-indent-level-directive 'safe-local-variable #'integerp)
 
+(defcustom verilog-indent-ignore-multiline-defines t
+  "Non-nil means ignore indentation on lines that are part of a multiline 
define."
+  :group 'verilog-mode-indent
+  :type 'boolean)
+(put 'verilog-indent-ignore-multiline-defines 'safe-local-variable 
#'verilog-booleanp)
+
+(defcustom verilog-indent-ignore-regexp nil
+  "Regexp that matches lines that should be ignored for indentation."
+  :group 'verilog-mode-indent
+  :type 'boolean)
+(put 'verilog-indent-ignore-regexp 'safe-local-variable #'stringp)
+
 (defcustom verilog-cexp-indent 2
   "Indentation of Verilog statements split across lines."
   :group 'verilog-mode-indent
@@ -723,6 +741,13 @@ Otherwise, line them up."
   :type 'boolean)
 (put 'verilog-indent-begin-after-if 'safe-local-variable #'verilog-booleanp)
 
+(defcustom verilog-indent-class-inside-pkg t
+  "Non-nil means indent classes inside packages.
+Otherwise, classes have zero indentation."
+  :group 'verilog-mode-indent
+  :type 'boolean)
+(put 'verilog-indent-class-inside-pkg 'safe-local-variable #'verilog-booleanp)
+
 (defcustom verilog-align-ifelse nil
   "Non-nil means align `else' under matching `if'.
 Otherwise else is lined up with first character on line holding matching if."
@@ -730,6 +755,38 @@ Otherwise else is lined up with first character on line 
holding matching if."
   :type 'boolean)
 (put 'verilog-align-ifelse 'safe-local-variable #'verilog-booleanp)
 
+(defcustom verilog-align-decl-expr-comments t
+  "Non-nil means align declaration and expressions comments."
+  :group 'verilog-mode-indent
+  :type 'boolean)
+(put 'verilog-align-decl-expr-comments 'safe-local-variable #'verilog-booleanp)
+
+(defcustom verilog-align-comment-distance 1
+  "Distance (in spaces) between longest declaration/expression and comments.
+Only works if `verilog-align-decl-expr-comments' is non-nil."
+  :group 'verilog-mode-indent
+  :type 'integer)
+(put 'verilog-align-comment-distance 'safe-local-variable #'integerp)
+
+(defcustom verilog-align-assign-expr nil
+  "Non-nil means align expressions of continuous assignments."
+  :group 'verilog-mode-indent
+  :type 'boolean)
+(put 'verilog-align-assign-expr 'safe-local-variable #'verilog-booleanp)
+
+(defcustom verilog-align-typedef-regexp nil
+  "Regexp that matches user typedefs for declaration alignment."
+  :group 'verilog-mode-indent
+  :type '(choice (regexp :tag "Regexp")
+                 (const :tag "None" nil)))
+(put 'verilog-align-typedef-regexp 'safe-local-variable #'stringp)
+
+(defcustom verilog-align-typedef-words nil
+  "List of words that match user typedefs for declaration alignment."
+  :group 'verilog-mode-indent
+  :type '(repeat string))
+(put 'verilog-align-typedef-words 'safe-local-variable #'listp)
+
 (defcustom verilog-minimum-comment-distance 10
   "Minimum distance (in lines) between begin and end required before a comment.
 Setting this variable to zero results in every end acquiring a comment; the
@@ -876,6 +933,12 @@ always be saved."
   :type 'boolean)
 (put 'verilog-auto-star-save 'safe-local-variable #'verilog-booleanp)
 
+(defcustom verilog-fontify-variables t
+  "Non-nil means fontify declaration variables."
+  :group 'verilog-mode-actions
+  :type 'boolean)
+(put 'verilog-fontify-variables 'safe-local-variable #'verilog-booleanp)
+
 (defvar verilog-auto-update-tick nil
   "Modification tick at which autos were last performed.")
 
@@ -1052,7 +1115,7 @@ You might want these defined in each file; put at the 
*END* of your file
 something like:
 
     // Local Variables:
-    // verilog-library-files:(\"/some/path/technology.v\" 
\"/some/path/tech2.v\")
+    // verilog-library-files:(\"/path/technology.v\" \"/path2/tech2.v\")
     // End:
 
 Verilog-mode attempts to detect changes to this local variable, but they
@@ -1124,7 +1187,7 @@ those temporaries reset.  See example in 
`verilog-auto-reset'."
 (put 'verilog-auto-reset-blocking-in-non 'safe-local-variable 
#'verilog-booleanp)
 
 (defcustom verilog-auto-reset-widths t
-  "True means AUTORESET should determine the width of signals.
+  "Non-nil means AUTORESET should determine the width of signals.
 This is then used to set the width of the zero (32'h0 for example).  This
 is required by some lint tools that aren't smart enough to ignore widths of
 the constant zero.  This may result in ugly code when parameters determine
@@ -1264,7 +1327,7 @@ See `verilog-auto-inst-param-value'."
 Also affects AUTOINSTPARAM.  Declaration order is the default for
 backward compatibility, and as some teams prefer signals that are
 declared together to remain together.  Sorted order reduces
-changes when declarations are moved around in a file. Sorting is
+changes when declarations are moved around in a file.  Sorting is
 within input/output/inout groupings, there is intentionally no
 option to intermix between input/output/inouts.
 
@@ -1275,7 +1338,7 @@ See also `verilog-auto-arg-sort'."
 (put 'verilog-auto-inst-sort 'safe-local-variable #'verilog-booleanp)
 
 (defcustom verilog-auto-inst-vector t
-  "True means when creating default ports with AUTOINST, use bus subscripts.
+  "Non-nil means when creating default ports with AUTOINST, use bus subscripts.
 If nil, skip the subscript when it matches the entire bus as declared in
 the module (AUTOWIRE signals always are subscripted, you must manually
 declare the wire to have the subscripts removed.)  Setting this to nil may
@@ -1515,10 +1578,9 @@ If set will become buffer local.")
     (define-key map "\C-c/"    #'verilog-star-comment)
     (define-key map "\C-c\C-c" #'verilog-comment-region)
     (define-key map "\C-c\C-u" #'verilog-uncomment-region)
-    (when (featurep 'xemacs)
-      (define-key map [(meta control h)] #'verilog-mark-defun)
-      (define-key map "\M-\C-a"  #'verilog-beg-of-defun)
-      (define-key map "\M-\C-e"  #'verilog-end-of-defun))
+    (define-key map "\M-\C-h"  #'verilog-mark-defun)
+    (define-key map "\M-\C-a"  #'verilog-beg-of-defun)
+    (define-key map "\M-\C-e"  #'verilog-end-of-defun)
     (define-key map "\C-c\C-d" #'verilog-goto-defun)
     (define-key map "\C-c\C-k" #'verilog-delete-auto)
     (define-key map "\C-c\C-a" #'verilog-auto)
@@ -2028,11 +2090,11 @@ Where __FLAGS__ appears in the string 
`verilog-current-flags'
 will be substituted.  Where __FILE__ appears in the string, the
 current buffer's file-name, without the directory portion, will
 be substituted."
-  (setq command        (verilog-string-replace-matches
+  (setq command (verilog-string-replace-matches
                 ;; Note \\b only works if under verilog syntax table
                 "\\b__FLAGS__\\b" (verilog-current-flags)
                 t t command))
-  (setq command        (verilog-string-replace-matches
+  (setq command (verilog-string-replace-matches
                 "\\b__FILE__\\b" (file-name-nondirectory
                                  (or (buffer-file-name) ""))
                 t t command))
@@ -2468,13 +2530,8 @@ find the errors."
 ;;
 ;; Regular expressions used to calculate indent, etc.
 ;;
-(defconst verilog-symbol-re      "\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>")
-;; Want to match
-;; aa :
-;; aa,bb :
-;; a[34:32] :
-;; a,
-;;   b :
+(defconst verilog-identifier-re "[a-zA-Z_][a-zA-Z_0-9]*")
+(defconst verilog-identifier-sym-re (concat "\\<" verilog-identifier-re "\\>"))
 (defconst verilog-assignment-operator-re
   (eval-when-compile
     (verilog-regexp-opt
@@ -2492,12 +2549,11 @@ find the errors."
        ) 't
          )))
 (defconst verilog-assignment-operation-re
-  (concat
-   ;; "\\(^\\s-*[A-Za-z0-9_]+\\(\\[\\([A-Za-z0-9_]+\\)\\]\\)*\\s-*\\)"
-   ;; "\\(^\\s-*[^=<>+-*/%&|^:\\s-]+[^=<>+-*/%&|^\n]*?\\)"
-   "\\(^.*?\\)" "\\B" verilog-assignment-operator-re "\\B" ))
+  (concat "\\(^.*?\\)" verilog-assignment-operator-re))
+(defconst verilog-assignment-operation-re-2
+  (concat "\\(.*?\\)" verilog-assignment-operator-re))
 
-(defconst verilog-label-re (concat verilog-symbol-re "\\s-*:\\s-*"))
+(defconst verilog-label-re (concat verilog-identifier-sym-re "\\s-*:\\s-*"))
 (defconst verilog-property-re
   (concat "\\(" verilog-label-re "\\)?"
           ;; "\\(assert\\|assume\\|cover\\)\\s-+property\\>"
@@ -2732,6 +2788,9 @@ find the errors."
            "\\|\\(\\<clocking\\>\\)"              ;17
            "\\|\\(\\<`[ou]vm_[a-z_]+_begin\\>\\)" ;18
            "\\|\\(\\<`vmm_[a-z_]+_member_begin\\>\\)"
+           "\\|\\(\\<`ifn?def\\>\\)"              ;20, matched end can be: 
`else `elsif `endif
+           "\\|\\(\\<`else\\>\\)"                 ;21, matched end can be: 
`endif
+           "\\|\\(\\<`elsif\\>\\)"                ;22, matched end can be: 
`else `endif
           ;;
           ))
 
@@ -2817,40 +2876,54 @@ find the errors."
        "localparam" "parameter" "var"
        ;; misc
        "string" "event" "chandle" "virtual" "enum" "genvar"
-       "struct" "union"
+       "struct" "union" "type"
        ;; builtin classes
        "mailbox" "semaphore"
        ))))
-(defconst verilog-declaration-re
-  (concat "\\(" verilog-declaration-prefix-re "\\s-*\\)?" 
verilog-declaration-core-re))
 (defconst verilog-range-re "\\(\\[[^]]*\\]\\s-*\\)+")
 (defconst verilog-optional-signed-re "\\s-*\\(\\(un\\)?signed\\)?")
 (defconst verilog-optional-signed-range-re
-  (concat
-   
"\\s-*\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?\\(\\<\\(un\\)?signed\\>\\s-*\\)?\\(" 
verilog-range-re "\\)?"))
+  (concat 
"\\s-*\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?\\(\\<\\(un\\)?signed\\>\\s-*\\)?\\(" 
verilog-range-re "\\)?"))
 (defconst verilog-macroexp-re "`\\sw+")
-
 (defconst verilog-delay-re 
"#\\s-*\\(\\([0-9_]+\\('s?[hdxbo][0-9a-fA-F_xz]+\\)?\\)\\|\\(([^()]*)\\)\\|\\(\\sw+\\)\\)")
-(defconst verilog-declaration-re-2-no-macro
-  (concat "\\s-*" verilog-declaration-re
-          "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" 
verilog-delay-re "\\)"
-          "\\)"))
-(defconst verilog-declaration-re-2-macro
-  (concat "\\s-*" verilog-declaration-re
-          "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" 
verilog-delay-re "\\)"
-          "\\|\\(" verilog-macroexp-re "\\)"
-          "\\)"))
-(defconst verilog-declaration-re-1-macro
-  (concat "^" verilog-declaration-re-2-macro))
-
-(defconst verilog-declaration-re-1-no-macro (concat "^" 
verilog-declaration-re-2-no-macro))
+(defconst verilog-interface-modport-re 
"\\(\\s-*\\([a-zA-Z0-9`_$]+\\.[a-zA-Z0-9`_$]+\\)[ \t\f]+\\)")
+(defconst verilog-comment-start-regexp "//\\|/\\*" "Dual comment value for 
`comment-start-regexp'.")
+(defconst verilog-typedef-enum-re
+  (concat "^\\s-*\\(typedef\\s-+\\)?enum\\(\\s-+" verilog-declaration-core-re 
verilog-optional-signed-range-re "\\)?"))
+
+(defconst verilog-declaration-simple-re
+  (concat "\\(" verilog-declaration-prefix-re "\\s-*\\)?" 
verilog-declaration-core-re))
+(defconst verilog-declaration-re
+  (concat "\\s-*" verilog-declaration-simple-re
+          "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" 
verilog-delay-re "\\)\\)"))
+(defconst verilog-declaration-re-macro
+  (concat "\\s-*" verilog-declaration-simple-re
+          "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" 
verilog-delay-re "\\)\\|\\(" verilog-macroexp-re "\\)\\)"))
+(defconst verilog-declaration-or-iface-mp-re
+  (concat "\\(" verilog-declaration-re "\\)\\|\\(" 
verilog-interface-modport-re "\\)"))
+(defconst verilog-declaration-embedded-comments-re
+  (concat "\\( " verilog-declaration-re "\\) ""\\s-*" "\\(" 
verilog-comment-start-regexp "\\)")
+  "Match expressions such as: input logic [7:0] /* auto enum sm_psm */ 
sm_psm;.")
 
 (defconst verilog-defun-re
   (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" 
"module" "class" "program" "interface" "package" "primitive" "config"))))
 (defconst verilog-end-defun-re
   (eval-when-compile (verilog-regexp-words '("endconnectmodule" "endmodule" 
"endclass" "endprogram" "endinterface" "endpackage" "endprimitive" 
"endconfig"))))
+(defconst verilog-defun-tf-re-beg
+  (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" 
"module" "class" "program" "interface" "package" "primitive" "config" 
"function" "task"))))
+(defconst verilog-defun-tf-re-end
+  (eval-when-compile (verilog-regexp-words '("endconnectmodule" "endmodule" 
"endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig" 
"endfunction" "endtask"))))
+(defconst verilog-defun-tf-re-all
+  (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" 
"module" "class" "program" "interface" "package" "primitive" "config" 
"function" "task"
+                                             "endconnectmodule" "endmodule" 
"endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig" 
"endfunction" "endtask"))))
+(defconst verilog-defun-no-class-re
+  (eval-when-compile (verilog-regexp-words '("macromodule" "connectmodule" 
"module" "program" "interface" "package" "primitive" "config"))))
+(defconst verilog-end-defun-no-class-re
+  (eval-when-compile (verilog-regexp-words '("endconnectmodule" "endmodule" 
"endprogram" "endinterface" "endpackage" "endprimitive" "endconfig"))))
 (defconst verilog-zero-indent-re
   (concat verilog-defun-re "\\|" verilog-end-defun-re))
+(defconst verilog-zero-indent-no-class-re
+  (concat verilog-defun-no-class-re "\\|" verilog-end-defun-no-class-re))
 (defconst verilog-inst-comment-re
   (eval-when-compile (verilog-regexp-words '("Outputs" "Inouts" "Inputs" 
"Interfaces" "Interfaced"))))
 
@@ -2983,19 +3056,38 @@ find the errors."
 (defconst verilog-extended-case-re 
"\\(\\(unique0?\\s-+\\|priority\\s-+\\)?case[xz]?\\|randcase\\)")
 (defconst verilog-extended-complete-re
   ;; verilog-beg-of-statement also looks backward one token to extend this 
match
-  (concat 
"\\(\\(\\<extern\\s-+\\|\\<\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?virtual\\s-+\\|\\<protected\\s-+\\|\\<static\\s-+\\)*\\(\\<function\\>\\|\\<task\\>\\)\\)"
+  (concat 
"\\(\\(\\<extern\\s-+\\|\\<\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?virtual\\s-+\\|\\<local\\s-+\\|\\<protected\\s-+\\|\\<static\\s-+\\)*\\(\\<function\\>\\|\\<task\\>\\)\\)"
          
"\\|\\(\\(\\<typedef\\>\\s-+\\)*\\(\\<struct\\>\\|\\<union\\>\\|\\<class\\>\\)\\)"
          
"\\|\\(\\(\\<\\(import\\|export\\)\\>\\s-+\\)?\\(\"DPI\\(-C\\)?\"\\s-+\\)?\\(\\<\\(pure\\|context\\)\\>\\s-+\\)?\\([A-Za-z_][A-Za-z0-9_]*\\s-*=\\s-*\\)?\\(function\\>\\|task\\>\\)\\)"
          "\\|" verilog-extended-case-re ))
+
+(eval-and-compile
+  (defconst verilog-basic-complete-words
+    '("always" "assign" "always_latch" "always_ff" "always_comb" "analog" 
"connectmodule" "constraint"
+      "import" "initial" "final" "module" "macromodule" "repeat" "randcase" 
"while"
+      "if" "for" "forever" "foreach" "else" "parameter" "do" "localparam" 
"assert" "default" "generate"))
+  (defconst verilog-basic-complete-words-expr
+    (let ((words verilog-basic-complete-words))
+      (dolist (word '("default" "parameter" "localparam"))
+        (setq words (remove word words)))
+      words))
+  (defconst verilog-basic-complete-words-expr-no-assign
+    (remove "assign" verilog-basic-complete-words-expr)))
+
 (defconst verilog-basic-complete-re
   (eval-when-compile
-    (verilog-regexp-words
-     '(
-       "always" "assign" "always_latch" "always_ff" "always_comb" "analog" 
"connectmodule" "constraint"
-       "import" "initial" "final" "module" "macromodule" "repeat" "randcase" 
"while"
-       "if" "for" "forever" "foreach" "else" "parameter" "do" "localparam" 
"assert"
-       ))))
-(defconst verilog-complete-reg
+    (verilog-regexp-words verilog-basic-complete-words)))
+
+(defconst verilog-basic-complete-expr-re
+  (eval-when-compile
+    (verilog-regexp-words verilog-basic-complete-words-expr)))
+
+(defconst verilog-basic-complete-expr-no-assign-re
+  (eval-when-compile
+    (verilog-regexp-words verilog-basic-complete-words-expr-no-assign)))
+
+
+(defconst verilog-complete-re
   (concat
    verilog-extended-complete-re "\\|\\(" verilog-basic-complete-re "\\)"))
 
@@ -3114,9 +3206,6 @@ find the errors."
             ))
   "List of Verilog keywords.")
 
-(defconst verilog-comment-start-regexp "//\\|/\\*"
-  "Dual comment value for `comment-start-regexp'.")
-
 (defvar verilog-mode-syntax-table
   (let ((table (make-syntax-table)))
     ;; Populate the syntax TABLE.
@@ -3338,12 +3427,12 @@ See also `verilog-font-lock-extra-types'.")
                 (list
                  
"\\<\\(\\(macro\\|connect\\)?module\\|primitive\\|class\\|program\\|interface\\|package\\|task\\)\\>\\s-*\\(\\sw+\\)"
                  '(1 font-lock-keyword-face)
-                 '(3 font-lock-function-name-face prepend))
+                 '(3 font-lock-function-name-face))
                 ;; Fontify function definitions
                 (list
                  (concat 
"\\<function\\>\\s-+\\(integer\\|real\\(time\\)?\\|time\\)\\s-+\\(\\sw+\\)" )
                   '(1 font-lock-keyword-face)
-                  '(3 font-lock-constant-face prepend))
+                  '(3 font-lock-constant-face))
                 '("\\<function\\>\\s-+\\(\\[[^]]+\\]\\)\\s-+\\(\\sw+\\)"
                   (1 font-lock-keyword-face)
                   (2 font-lock-constant-face append))
@@ -3358,12 +3447,12 @@ See also `verilog-font-lock-extra-types'.")
                    ;; Pre-form for this anchored matcher:
                    ;; First, avoid declaration keywords written in comments,
                    ;; which can also trigger this anchor.
-                   '(if (not (verilog-in-comment-p))
+                   '(if (and (not (verilog-in-comment-p))
+                             (not (member (thing-at-point 'symbol) 
verilog-keywords)))
                         (verilog-single-declaration-end 
verilog-highlight-max-lookahead)
                       (point)) ;; => current declaration statement is of 0 
length
                    nil ;; Post-form: nothing to be done
-                   '(0 font-lock-variable-name-face t t)))
-                )))
+                   '(0 font-lock-variable-name-face))))))
 
 
   (setq verilog-font-lock-keywords-2
@@ -3617,7 +3706,7 @@ inserted using a single call to `verilog-insert'."
 (defun verilog-single-declaration-end (limit)
   "Return pos where current (single) declaration statement ends.
 Also, this function moves POINT forward to the start of a variable name
-(skipping the range-part and whitespace).
+\(skipping the range-part and whitespace).
 Function expected to be called with POINT just after a declaration keyword.
 LIMIT sets the max POINT for searching and moving to.  No such limit if LIMIT
 is 0.
@@ -3629,8 +3718,6 @@ Meaning of *single* declaration:
 and `output [1:0] y' is the other single declaration.  In the 1st single
 declaration, POINT is moved to start of `clk'.  And in the 2nd declaration,
 POINT is moved to `y'."
-
-
   (let (maxpoint old-point)
     ;; maxpoint = min(curr-point + limit, buffer-size)
     (setq maxpoint (if (eq limit 0)
@@ -3651,7 +3738,7 @@ POINT is moved to `y'."
                   (not (eq old-point (point)))
                   (not (eq (char-after) ?\; ))
                   (not (eq (char-after) ?\) ))
-                  (not (looking-at verilog-declaration-re)))
+                  (not (looking-at (verilog-get-declaration-re))))
         (setq old-point (point))
         (ignore-errors
           (forward-sexp)
@@ -3669,31 +3756,28 @@ This function moves POINT to the next variable within 
the same declaration (if
 it exists).
 LIMIT is expected to be the pos at which current single-declaration ends,
 obtained using `verilog-single-declaration-end'."
-
-  (let (found-var old-point)
-
-    ;; Remove starting whitespace
-    (verilog-forward-ws&directives limit)
-
-    (when (< (point) limit) ;; no matching if this is violated
-
-      ;; Find the variable name (match-data is set here)
-      (setq found-var (re-search-forward verilog-symbol-re limit t))
-
-      ;; Walk to this variable's delimiter
-      (save-match-data
-        (verilog-forward-ws&directives limit)
-        (setq old-point nil)
-        (while (and (< (point) limit)
-                    (not (member (char-after) '(?, ?\) ?\;)))
-                    (not (eq old-point (point))))
-          (setq old-point (point))
+  (when (and verilog-fontify-variables
+             (not (member (thing-at-point 'symbol) verilog-keywords)))
+    (let (found-var old-point)
+      ;; Remove starting whitespace
+      (verilog-forward-ws&directives limit)
+      (when (< (point) limit) ;; no matching if this is violated
+        ;; Find the variable name (match-data is set here)
+        (setq found-var (re-search-forward verilog-identifier-sym-re limit t))
+        ;; Walk to this variable's delimiter
+        (save-match-data
           (verilog-forward-ws&directives limit)
-          (forward-sexp)
-          (verilog-forward-ws&directives limit))
-        ;; Only a comma or semicolon expected at this point
-        (skip-syntax-forward "."))
-      found-var)))
+          (setq old-point nil)
+          (while (and (< (point) limit)
+                      (not (member (char-after) '(?, ?\) ?\] ?\} ?\;)))
+                      (not (eq old-point (point))))
+            (setq old-point (point))
+            (verilog-forward-ws&directives limit)
+            (forward-sexp)
+            (verilog-forward-ws&directives limit))
+          ;; Only a comma or semicolon expected at this point
+          (skip-syntax-forward "."))
+        found-var))))
 
 (defun verilog-point-text (&optional pointnum)
   "Return text describing where POINTNUM or current point is (for errors).
@@ -3728,9 +3812,14 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
        (elsec 1)
        (found nil)
        (st (point)))
-    (if (not (looking-at "\\<"))
-       (forward-word-strictly -1))
+    (unless (looking-at "\\<")
+      (forward-word-strictly -1))
     (cond
+     ((save-excursion
+        (goto-char st)
+        (member (preceding-char) '(?\) ?\} ?\])))
+      (goto-char st)
+      (backward-sexp 1))
      ((verilog-skip-backward-comment-or-string))
      ((looking-at "\\<else\\>")
       (setq reg (concat
@@ -3754,7 +3843,17 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
              (setq found 't))))))
      ((looking-at verilog-end-block-re)
       (verilog-leap-to-head))
-     ((looking-at 
"\\(endmodule\\>\\)\\|\\(\\<endprimitive\\>\\)\\|\\(\\<endclass\\>\\)\\|\\(\\<endprogram\\>\\)\\|\\(\\<endinterface\\>\\)\\|\\(\\<endpackage\\>\\)\\|\\(\\<endconnectmodule\\>\\)")
+     (;; Fallback, when current word does not match `verilog-end-block-re'
+      (looking-at (concat
+                   "\\(\\<endmodule\\>\\)\\|"        ; 1
+                   "\\(\\<endprimitive\\>\\)\\|"     ; 2
+                   "\\(\\<endclass\\>\\)\\|"         ; 3
+                   "\\(\\<endprogram\\>\\)\\|"       ; 4
+                   "\\(\\<endinterface\\>\\)\\|"     ; 5
+                   "\\(\\<endpackage\\>\\)\\|"       ; 6
+                   "\\(\\<endconnectmodule\\>\\)\\|" ; 7
+                   "\\(\\<endchecker\\>\\)\\|"       ; 8
+                   "\\(\\<endconfig\\>\\)"))         ; 9
       (cond
        ((match-end 1)
        (verilog-re-search-backward "\\<\\(macro\\)?module\\>" nil 'move))
@@ -3769,7 +3868,11 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
        ((match-end 6)
        (verilog-re-search-backward "\\<package\\>" nil 'move))
        ((match-end 7)
-       (verilog-re-search-backward "\\<connectmodule\\>" nil 'move))
+        (verilog-re-search-backward "\\<connectmodule\\>" nil 'move))
+       ((match-end 8)
+        (verilog-re-search-backward "\\<checker\\>" nil 'move))
+       ((match-end 9)
+        (verilog-re-search-backward "\\<config\\>" nil 'move))
        (t
        (goto-char st)
        (backward-sexp 1))))
@@ -3782,9 +3885,14 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
        (md 2)
        (st (point))
        (nest 'yes))
-    (if (not (looking-at "\\<"))
-       (forward-word-strictly -1))
+    (unless (looking-at "\\<")
+      (forward-word-strictly -1))
     (cond
+     ((save-excursion
+        (goto-char st)
+        (member (following-char) '(?\( ?\{ ?\[)))
+      (goto-char st)
+      (forward-sexp 1))
      ((verilog-skip-forward-comment-or-string)
       (verilog-forward-syntactic-ws))
      ((looking-at verilog-beg-block-re-ordered)
@@ -3843,22 +3951,31 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
         ;; Search forward for matching endtask
         (setq reg "\\<endtask\\>" )
         (setq nest 'no))
-       ((match-end 12)
+       ((match-end 13)
         ;; Search forward for matching endgenerate
         (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" ))
-       ((match-end 13)
+       ((match-end 14)
         ;; Search forward for matching endgroup
         (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" ))
-       ((match-end 14)
+       ((match-end 15)
         ;; Search forward for matching endproperty
         (setq reg "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" ))
-       ((match-end 15)
+       ((match-end 16)
         ;; Search forward for matching endsequence
         (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" )
         (setq md 3)) ; 3 to get to endsequence in the reg above
        ((match-end 17)
         ;; Search forward for matching endclocking
-        (setq reg "\\(\\<clocking\\>\\)\\|\\(\\<endclocking\\>\\)" )))
+        (setq reg "\\(\\<clocking\\>\\)\\|\\(\\<endclocking\\>\\)" ))
+       ((match-end 20)
+        ;; Search forward for matching `ifn?def, can be `else `elseif or `endif
+        (setq reg 
"\\(\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\|\\<`else\\>\\|\\<`elsif\\>\\)" ))
+       ((match-end 21)
+        ;; Search forward for matching `else, can be `endif
+        (setq reg "\\(\\<`else\\>\\|\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\)" ))
+       ((match-end 22)
+        ;; Search forward for matching `elsif, can be `else or `endif, DONT 
support `elsif
+        (setq reg 
"\\(\\<`elsif\\>\\|\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\|\\<`else\\>\\)" )))
       (if (and reg
               (forward-word-strictly 1))
          (catch 'skip
@@ -3867,15 +3984,26 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
                      here)
                  (while (verilog-re-search-forward reg nil 'move)
                    (cond
-                    ((match-end md) ; a closer in regular expression, so we 
are climbing out
+                     ((and (or (match-end md)
+                               (and (member (match-string-no-properties 1) 
'("`else" "`elsif"))
+                                    (= 1 depth)))
+                           (or (and (member (match-string-no-properties 2) 
'("`else" "`elsif"))
+                                    (= 1 depth))
+                               ;; stop at `else/`elsif which matching ifn?def 
(or `elsif with same depth)
+                               ;; a closer in regular expression, so we are 
climbing out
+                               (not (member (match-string-no-properties 2) 
'("`else" "`elsif")))))
                      (setq depth (1- depth))
                      (if (= 0 depth) ; we are out!
                          (throw 'skip 1)))
-                    ((match-end 1) ; an opener in the r-e, so we are in deeper 
now
+                     ((and (match-end 1)  ; an opener in the r-e, so we are in 
deeper now
+                           (not (member (match-string-no-properties 1) 
'("`else" "`elsif"))))
                      (setq here (point)) ; remember where we started
                      (goto-char (match-beginning 1))
                      (cond
-                      ((if (or
+                       ((verilog-looking-back "\\(\\<typedef\\>\\s-+\\)" 
(point-at-bol))
+                        ;; avoid nesting for typedef class defs
+                        (forward-word-strictly 1))
+                       ((if (or
                             (looking-at verilog-disable-fork-re)
                             (and (looking-at "fork")
                                  (progn
@@ -3890,28 +4018,37 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
                  (throw 'skip 1))))))
 
      ((looking-at (concat
-                  "\\(\\<\\(macro\\)?module\\>\\)\\|"
-                  "\\(\\<primitive\\>\\)\\|"
-                  "\\(\\<class\\>\\)\\|"
-                  "\\(\\<program\\>\\)\\|"
-                  "\\(\\<interface\\>\\)\\|"
-                  "\\(\\<package\\>\\)\\|"
-                  "\\(\\<connectmodule\\>\\)"))
+                   "\\(\\<\\(macro\\)?module\\>\\)\\|"                         
; 1,2
+                   "\\(\\<primitive\\>\\)\\|"                                  
; 3
+                   "\\(\\(\\(interface\\|virtual\\)\\s-+\\)?\\<class\\>\\)\\|" 
; 4,5,6
+                   "\\(\\<program\\>\\)\\|"                                    
; 7
+                   "\\(\\<interface\\>\\)\\|"                                  
; 8
+                   "\\(\\<package\\>\\)\\|"                                    
; 9
+                   "\\(\\<connectmodule\\>\\)\\|"                              
; 10
+                   "\\(\\<generate\\>\\)\\|"                                   
; 11
+                   "\\(\\<checker\\>\\)\\|"                                    
; 12
+                   "\\(\\<config\\>\\)"))                                      
; 13
       (cond
        ((match-end 1)
        (verilog-re-search-forward "\\<endmodule\\>" nil 'move))
-       ((match-end 2)
-       (verilog-re-search-forward "\\<endprimitive\\>" nil 'move))
        ((match-end 3)
-       (verilog-re-search-forward "\\<endclass\\>" nil 'move))
+       (verilog-re-search-forward "\\<endprimitive\\>" nil 'move))
        ((match-end 4)
+       (verilog-re-search-forward "\\<endclass\\>" nil 'move))
+       ((match-end 7)
        (verilog-re-search-forward "\\<endprogram\\>" nil 'move))
-       ((match-end 5)
+       ((match-end 8)
        (verilog-re-search-forward "\\<endinterface\\>" nil 'move))
-       ((match-end 6)
+       ((match-end 9)
        (verilog-re-search-forward "\\<endpackage\\>" nil 'move))
-       ((match-end 7)
-       (verilog-re-search-forward "\\<endconnectmodule\\>" nil 'move))
+       ((match-end 10)
+        (verilog-re-search-forward "\\<endconnectmodule\\>" nil 'move))
+       ((match-end 11)
+        (verilog-re-search-forward "\\<endgenerate\\>" nil 'move))
+       ((match-end 12)
+        (verilog-re-search-forward "\\<endchecker\\>" nil 'move))
+       ((match-end 13)
+        (verilog-re-search-forward "\\<endconfig\\>" nil 'move))
        (t
        (goto-char st)
        (if (= (following-char) ?\) )
@@ -3924,11 +4061,69 @@ Use filename, if current buffer being edited shorten to 
just buffer name."
        (forward-sexp 1))))))
 
 (defun verilog-declaration-beg ()
-  (verilog-re-search-backward verilog-declaration-re (bobp) t))
-
-;;
-;;
-;;  Mode
+  (verilog-re-search-backward (verilog-get-declaration-re) (bobp) t))
+
+(defun verilog-align-typedef-enabled-p ()
+  "Return non-nil if alignment of user typedefs is enabled.
+This will be automatically set when either `verilog-align-typedef-regexp'
+or `verilog-align-typedef-words' are non-nil."
+  (when (or verilog-align-typedef-regexp
+            verilog-align-typedef-words)
+    t))
+
+(defun verilog-get-declaration-typedef-re ()
+  "Return regexp of a user defined typedef.
+See `verilog-align-typedef-regexp' and `verilog-align-typedef-words'."
+  (let (typedef-re words words-re re)
+    (when (verilog-align-typedef-enabled-p)
+      (setq typedef-re verilog-align-typedef-regexp)
+      (setq words verilog-align-typedef-words)
+      (setq words-re (verilog-regexp-words verilog-align-typedef-words))
+      (cond ((and typedef-re (not words))
+             (setq re typedef-re))
+            ((and (not typedef-re) words)
+             (setq re words-re))
+            ((and typedef-re words)
+             (setq re (concat verilog-align-typedef-regexp "\\|" words-re))))
+      (concat "\\s-*" "\\(" verilog-declaration-prefix-re "\\s-*\\(" 
verilog-range-re "\\)?" "\\s-*\\)?"
+              (concat "\\(" re "\\)")
+              "\\(\\s-*" verilog-range-re "\\)?\\s-+"))))
+
+(defun verilog-get-declaration-re (&optional type)
+  "Return declaration regexp depending on customizable variables and TYPE."
+  (let ((re (cond ((equal type 'iface-mp)
+                   verilog-declaration-or-iface-mp-re)
+                  ((equal type 'embedded-comments)
+                   verilog-declaration-embedded-comments-re)
+                  (verilog-indent-declaration-macros
+                   verilog-declaration-re-macro)
+                  (t
+                   verilog-declaration-re))))
+    (when (and (verilog-align-typedef-enabled-p)
+               (or (string= re verilog-declaration-or-iface-mp-re)
+                   (string= re verilog-declaration-re)))
+      (setq re (concat "\\(" (verilog-get-declaration-typedef-re) "\\)\\|\\(" 
re "\\)")))
+    re))
+
+(defun verilog-looking-at-decl-to-align ()
+  "Return non-nil if pointing at a Verilog variable declaration that must be 
aligned."
+  (let* ((re (verilog-get-declaration-re))
+         (valid-re (looking-at re))
+         (id-pos (match-end 0)))
+    (and valid-re
+         (not (verilog-at-struct-decl-p))
+         (not (verilog-at-enum-decl-p))
+         (save-excursion
+           (goto-char id-pos)
+           (verilog-forward-syntactic-ws)
+           (and (not (looking-at ";"))
+                (not (member (thing-at-point 'symbol) verilog-keywords))
+                (progn ; Avoid alignment of instances whose name match user 
defined types
+                  (forward-word)
+                  (verilog-forward-syntactic-ws)
+                  (not (looking-at "("))))))))
+
+;;; Mode:
 ;;
 (defvar verilog-which-tool 1)
 ;;;###autoload
@@ -3965,6 +4160,11 @@ Variables controlling indentation/edit style:
    function keyword.
  `verilog-indent-level-directive'     (default 1)
    Indentation of \\=`ifdef/\\=`endif blocks.
+ `verilog-indent-ignore-multiline-defines' (default t)
+   Non-nil means ignore indentation on lines that are part of a multiline
+   define.
+ `verilog-indent-ignore-regexp'     (default nil
+   Regexp that matches lines that should be ignored for indentation.
  `verilog-cexp-indent'              (default 1)
    Indentation of Verilog statements broken across lines i.e.:
       if (a)
@@ -3988,6 +4188,9 @@ Variables controlling indentation/edit style:
    otherwise you get:
       if (a)
       begin
+ `verilog-indent-class-inside-pkg'  (default t)
+   Non-nil means indent classes inside packages.
+   Otherwise, classes have zero indentation.
  `verilog-auto-endcomments'         (default t)
    Non-nil means a comment /* ... */ is set after the ends which ends
    cases, tasks, functions and modules.
@@ -3997,6 +4200,17 @@ Variables controlling indentation/edit style:
    will be inserted.  Setting this variable to zero results in every
    end acquiring a comment; the default avoids too many redundant
    comments in tight quarters.
+ `verilog-align-decl-expr-comments' (default t)
+   Non-nil means align declaration and expressions comments.
+ `verilog-align-comment-distance'   (default 1)
+   Distance (in spaces) between longest declaration and comments.
+   Only works if `verilog-align-decl-expr-comments' is non-nil.
+ `verilog-align-assign-expr'        (default nil)
+   Non-nil means align expressions of continuous assignments.
+ `verilog-align-typedef-regexp'     (default nil)
+   Regexp that matches user typedefs for declaration alignment.
+ `verilog-align-typedef-words'      (default nil)
+   List of words that match user typedefs for declaration alignment.
  `verilog-auto-lineup'              (default `declarations')
    List of contexts where auto lineup of code should be done.
 
@@ -4020,17 +4234,20 @@ Some other functions are:
     \\[verilog-mark-defun]  Mark function.
     \\[verilog-beg-of-defun]  Move to beginning of current function.
     \\[verilog-end-of-defun]  Move to end of current function.
-    \\[verilog-label-be]  Label matching begin ... end, fork ... join, etc 
statements.
+    \\[verilog-label-be]  Label matching begin ... end, fork ... join, etc
+                          statements.
 
     \\[verilog-comment-region]  Put marked area in a comment.
-    \\[verilog-uncomment-region]  Uncomment an area commented with 
\\[verilog-comment-region].
+    \\[verilog-uncomment-region]  Uncomment an area commented with
+                                  \\[verilog-comment-region].
     \\[verilog-insert-block]  Insert begin ... end.
     \\[verilog-star-comment]    Insert /* ... */.
 
     \\[verilog-sk-always]  Insert an always @(AS) begin .. end block.
     \\[verilog-sk-begin]  Insert a begin .. end block.
     \\[verilog-sk-case]  Insert a case block, prompting for details.
-    \\[verilog-sk-for]  Insert a for (...) begin .. end block, prompting for 
details.
+    \\[verilog-sk-for]  Insert a for (...) begin .. end block, prompting for
+                        details.
     \\[verilog-sk-generate]  Insert a generate .. endgenerate block.
     \\[verilog-sk-header]  Insert a header block at the top of file.
     \\[verilog-sk-initial]  Insert an initial begin .. end block.
@@ -4053,14 +4270,17 @@ Some other functions are:
     \\[verilog-sk-else-if]  Insert an else if (..) begin .. end block.
     \\[verilog-sk-comment]  Insert a comment block.
     \\[verilog-sk-assign]  Insert an assign .. = ..; statement.
-    \\[verilog-sk-function]  Insert a function .. begin .. end endfunction 
block.
+    \\[verilog-sk-function]  Insert a function .. begin .. end endfunction
+                             block.
     \\[verilog-sk-input]  Insert an input declaration, prompting for details.
     \\[verilog-sk-output]  Insert an output declaration, prompting for details.
-    \\[verilog-sk-state-machine]  Insert a state machine definition, prompting 
for details.
+    \\[verilog-sk-state-machine]  Insert a state machine definition, prompting
+                                  for details.
     \\[verilog-sk-inout]  Insert an inout declaration, prompting for details.
     \\[verilog-sk-wire]  Insert a wire declaration, prompting for details.
     \\[verilog-sk-reg]  Insert a register declaration, prompting for details.
-    \\[verilog-sk-define-signal]  Define signal under point as a register at 
the top of the module.
+    \\[verilog-sk-define-signal]  Define signal under point as a register at
+                                  the top of the module.
 
 All key bindings can be seen in a Verilog-buffer with \\[describe-bindings].
 Key bindings specific to `verilog-mode-map' are:
@@ -4147,7 +4367,7 @@ Key bindings specific to `verilog-mode-map' are:
   ;; verilog-mode-hook call added by define-derived-mode
   )
 
-;;; Integration with the speedbar
+;;; Integration with the speedbar:
 ;;
 
 ;; Avoid problems with XEmacs byte-compiles.
@@ -4427,15 +4647,24 @@ following code fragment:
   "Mark the current Verilog function (or procedure).
 This puts the mark at the end, and point at the beginning."
   (interactive)
-  (if (featurep 'xemacs)
-      (progn
-       (push-mark)
-       (verilog-end-of-defun)
-       (push-mark)
-       (verilog-beg-of-defun)
-       (if (fboundp 'zmacs-activate-region)
-           (zmacs-activate-region)))
-    (mark-defun)))
+  (let (found)
+    (if (featurep 'xemacs)
+        (progn
+          (push-mark)
+          (verilog-end-of-defun)
+          (push-mark)
+          (verilog-beg-of-defun)
+          (if (fboundp 'zmacs-activate-region)
+              (zmacs-activate-region)))
+      ;; GNU Emacs
+      (when (verilog-beg-of-defun)
+        (setq found (point))
+        (verilog-end-of-defun)
+        (end-of-line)
+        (push-mark)
+        (goto-char found)
+        (beginning-of-line)
+        (setq mark-active t)))))
 
 (defun verilog-comment-region (start end)
   ;; checkdoc-params: (start end)
@@ -4514,7 +4743,21 @@ area.  See also `verilog-comment-region'."
 (defun verilog-beg-of-defun ()
   "Move backward to the beginning of the current function or procedure."
   (interactive)
-  (verilog-re-search-backward verilog-defun-re nil 'move))
+  (let (found)
+    (save-excursion
+      (when (verilog-looking-back verilog-defun-tf-re-end (point-at-bol))
+        (verilog-backward-sexp)
+        (setq found (point)))
+      (while (and (not found)
+                  (verilog-re-search-backward verilog-defun-tf-re-all nil t))
+        (cond ((verilog-looking-back "\\(\\<typedef\\>\\s-+\\)" 
(point-at-bol)) ; corner case, e.g. 'typedef class <id>;'
+               (backward-word))
+              ((looking-at verilog-defun-tf-re-end)
+               (verilog-backward-sexp))
+              ((looking-at verilog-defun-tf-re-beg)
+               (setq found (point))))))
+    (when found
+      (goto-char found))))
 
 (defun verilog-beg-of-defun-quick ()
   "Move backward to the beginning of the current function or procedure.
@@ -4525,7 +4768,10 @@ Uses `verilog-scan' cache."
 (defun verilog-end-of-defun ()
   "Move forward to the end of the current function or procedure."
   (interactive)
-  (verilog-re-search-forward verilog-end-defun-re nil 'move))
+  (when (or (looking-at verilog-defun-tf-re-beg)
+            (verilog-beg-of-defun))
+    (verilog-forward-sexp)
+    (point)))
 
 (defun verilog-get-end-of-defun ()
   (save-excursion
@@ -4542,10 +4788,10 @@ Uses `verilog-scan' cache."
        (case-fold-search nil)
        (oldpos (point))
        (b (progn
-            (verilog-beg-of-defun)
+            (verilog-re-search-backward verilog-defun-re nil 'move)
             (point-marker)))
        (e (progn
-            (verilog-end-of-defun)
+            (verilog-re-search-forward verilog-end-defun-re nil 'move)
             (point-marker))))
     (goto-char (marker-position b))
     (if (> (- e b) 200)
@@ -4605,19 +4851,18 @@ Uses `verilog-scan' cache."
                 (goto-char h)))
              ;; stop if we see an extended complete reg, perhaps a complete one
              (and
-              (looking-at verilog-complete-reg)
+              (looking-at verilog-complete-re)
               (let* ((p (point)))
                 (while (and (looking-at verilog-extended-complete-re)
                             (progn (setq p (point))
                                    (verilog-backward-token)
                                    (/= p (point)))))
                 (goto-char p)))
-             ;; stop if we see a complete reg (previous found extended ones)
-             (looking-at verilog-basic-complete-re)
              ;; stop if previous token is an ender
              (save-excursion
                (verilog-backward-token)
-               (looking-at verilog-end-block-re))))
+               (or (looking-at verilog-end-block-re)
+                    (verilog-in-directive-p)))))
       (verilog-backward-syntactic-ws)
       (verilog-backward-token))
     ;; Now point is where the previous line ended.
@@ -4634,28 +4879,23 @@ Uses `verilog-scan' cache."
       (verilog-backward-syntactic-ws))
   (let ((pt (point)))
     (catch 'done
-      (while (not (looking-at verilog-complete-reg))
+      (while (not (looking-at verilog-complete-re))
         (setq pt (point))
         (verilog-backward-syntactic-ws)
         (if (or (bolp)
                 (= (preceding-char) ?\;)
+                (and (= (preceding-char) ?\{)
+                     (save-excursion
+                       (backward-char)
+                       (verilog-at-struct-p)))
                (progn
                  (verilog-backward-token)
-                 (looking-at verilog-ends-re)))
+                  (or (looking-at verilog-ends-re)
+                      (looking-at "begin"))))
             (progn
               (goto-char pt)
               (throw 'done t)))))
     (verilog-forward-syntactic-ws)))
-;;
-;;      (while (and
-;;              (not (looking-at verilog-complete-reg))
-;;              (not (bolp))
-;;              (not (= (preceding-char) ?\;)))
-;;        (verilog-backward-token)
-;;        (verilog-backward-syntactic-ws)
-;;        (setq pt (point)))
-;;      (goto-char pt)
-;;   ;(verilog-forward-syntactic-ws)
 
 (defun verilog-end-of-statement ()
   "Move forward to end of current statement."
@@ -4713,7 +4953,7 @@ Uses `verilog-scan' cache."
         pos)))))
 
 (defun verilog-in-case-region-p ()
-  "Return true if in a case region.
+  "Return non-nil if in a case region.
 More specifically, point @ in the line foo : @ begin"
   (interactive)
   (save-excursion
@@ -4758,37 +4998,29 @@ More specifically, point @ in the line foo : @ begin"
     (forward-sexp arg)))
 
 (defun verilog-in-generate-region-p ()
-  "Return true if in a generate region.
+  "Return non-nil if in a generate region.
 More specifically, after a generate and before an endgenerate."
   (interactive)
-  (let ((nest 1))
-    (save-excursion
-      (catch 'done
-       (while (and
-               (/= nest 0)
-               (verilog-re-search-backward
-                
"\\<\\(module\\)\\|\\(connectmodule\\)\\|\\(generate\\)\\|\\(endgenerate\\)\\|\\(if\\)\\|\\(case\\)\\|\\(for\\)\\>"
 nil 'move)
-               (cond
-                ((match-end 1) ; module - we have crawled out
-                 (throw 'done 1))
-                ((match-end 2) ; connectmodule - we have crawled out
-                 (throw 'done 1))
-                ((match-end 3) ; generate
-                 (setq nest (1- nest)))
-                ((match-end 4) ; endgenerate
-                 (setq nest (1+ nest)))
-                ((match-end 5) ; if
-                 (setq nest (1- nest)))
-                ((match-end 6) ; case
-                 (setq nest (1- nest)))
-                ((match-end 7) ; for
-                 (setq nest (1- nest))))))))
-    (= nest 0) )) ; return nest
+  (let ((pos (point))
+        gen-beg-point gen-end-point)
+    (save-match-data
+      (save-excursion
+        (and (verilog-re-search-backward "\\<\\(generate\\)\\>" nil t)
+             (forward-word)
+             (setq gen-beg-point (point))
+             (verilog-forward-sexp)
+             (backward-word)
+             (setq gen-end-point (point)))))
+    (if (and gen-beg-point gen-end-point
+             (>= pos gen-beg-point)
+             (<= pos gen-end-point))
+        t
+      nil)))
 
 (defun verilog-in-fork-region-p ()
-  "Return true if between a fork and join."
+  "Return non-nil if between a fork and join."
   (interactive)
-  (let ((lim (save-excursion (verilog-beg-of-defun)  (point)))
+  (let ((lim (save-excursion (verilog-re-search-backward verilog-defun-re nil 
'move)  (point)))
        (nest 1))
     (save-excursion
       (while (and
@@ -4802,7 +5034,7 @@ More specifically, after a generate and before an 
endgenerate."
     (= nest 0) )) ; return nest
 
 (defun verilog-in-deferred-immediate-final-p ()
-  "Return true if inside an `assert/assume/cover final' statement."
+  "Return non-nil if inside an `assert/assume/cover final' statement."
   (interactive)
   (and (looking-at "final")
        (verilog-looking-back "\\<\\(?:assert\\|assume\\|cover\\)\\>\\s-+" nil))
@@ -5013,7 +5245,7 @@ primitive or interface named NAME."
                             (insert str)
                             (ding 't))
                         (let ((lim
-                               (save-excursion (verilog-beg-of-defun) (point)))
+                               (save-excursion (verilog-re-search-backward 
verilog-defun-re nil 'move) (point)))
                               (here (point)))
                           (cond
                            (;-- handle named block differently
@@ -5461,7 +5693,7 @@ For example:
 becomes:
         // surefire lint_line_off UDDONX"
   (interactive)
-  (let ((buff (if (boundp 'next-error-last-buffer) ;Added to Emacs-22.1
+  (let ((buff (if (boundp 'next-error-last-buffer)  ; Added to Emacs-22.1
                   next-error-last-buffer
                 (verilog--suppressed-warnings
                     ((obsolete compilation-last-buffer))
@@ -5585,13 +5817,14 @@ FILENAME to find directory to run in, or defaults to 
`buffer-file-name'."
 (defun verilog-warn-error (string &rest args)
   "Call `error' using STRING and optional ARGS.
 If `verilog-warn-fatal' is non-nil, call `verilog-warn' instead."
-  (apply (if verilog-warn-fatal #'error #'verilog-warn)
+  (apply (if (and verilog-warn-fatal verilog-warn-fatal-internal)
+             #'error #'verilog-warn)
          string args))
 
 (defmacro verilog-batch-error-wrapper (&rest body)
   "Execute BODY and add error prefix to any errors found.
 This lets programs calling batch mode to easily extract error messages."
-  `(let ((verilog-warn-fatal nil))
+  `(let ((verilog-warn-fatal-internal nil))
      (condition-case err
         (progn ,@body)
        (error
@@ -5721,7 +5954,7 @@ This sets up the appropriate Verilog mode environment, 
calls
     (string      . 0)))
 
 (defun verilog-continued-line-1 (lim)
-  "Return true if this is a continued line.
+  "Return non-nil if this is a continued line.
 Set point to where line starts.  Limit search to point LIM."
   (let ((continued 't))
     (if (eq 0 (forward-line -1))
@@ -5774,7 +6007,6 @@ Return a list of two elements: (INDENT-TYPE 
INDENT-LEVEL)."
                    ;; if we are in a parenthesized list, and the user likes to 
indent these, return.
                    ;; unless we are in the newfangled coverpoint or constraint 
blocks
                    (if (and
-                        verilog-indent-lists
                         (verilog-in-paren)
                         (not (verilog-in-coverage-p))
                         )
@@ -5791,7 +6023,7 @@ Return a list of two elements: (INDENT-TYPE 
INDENT-LEVEL)."
                                   (looking-at verilog-in-constraint-re) ))  ; 
may still get hosed if concat in constraint
                          (let ((sp (point)))
                            (if (and
-                                (not (looking-at verilog-complete-reg))
+                                (not (looking-at verilog-complete-re))
                                 (verilog-continued-line-1 lim))
                                (progn (goto-char sp)
                                       (throw 'nesting 'cexp))
@@ -5996,6 +6228,12 @@ Return a list of two elements: (INDENT-TYPE 
INDENT-LEVEL)."
                        (goto-char here) ; or is clocking, starts a new block
                        (throw 'nesting 'block)))))
 
+             ;; if find `ifn?def `else `elsif
+             ((or (match-end 20)
+                  (match-end 21)
+                  (match-end 22))
+              (throw 'continue 'foo))
+
              ((looking-at "\\<class\\|struct\\|function\\|task\\>")
               ;; *sigh* These words have an optional prefix:
               ;; extern {virtual|protected}? function a();
@@ -6025,7 +6263,7 @@ Return a list of two elements: (INDENT-TYPE 
INDENT-LEVEL)."
               ;;    {assert|assume|cover} property (); are complete
               ;;   and could also be labeled: - foo: assert property
               ;; but
-              ;;    property ID () ... needs end_property
+              ;;    property ID () ... needs endproperty
               (verilog-beg-of-statement)
               (if (looking-at verilog-property-re)
                   (throw 'continue 'statement) ; We don't need an endproperty 
for these
@@ -6110,6 +6348,23 @@ of the appropriate enclosing block."
        (ding 't)
        (setq nest 0))))))
 
+(defun verilog-leap-to-class-head ()
+  (let ((nest 1)
+        (class-re (concat "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)")))
+    (catch 'skip
+      (while (verilog-re-search-backward class-re nil 'move)
+        (cond
+         ((match-end 1) ; begin
+          (when (verilog-looking-back 
"\\(\\<interface\\>\\s-+\\)\\|\\(\\<virtual\\>\\s-+\\)" (point-at-bol))
+            (goto-char (match-beginning 0)))
+          (unless (verilog-looking-back "\\<typedef\\>\\s-+" (point-at-bol))
+            (setq nest (1- nest))
+            (if (= 0 nest)
+               ;; Now previous line describes syntax
+               (throw 'skip 1))))
+        ((match-end 2) ; end
+          (setq nest (1+ nest))))))))
+
 (defun verilog-leap-to-head ()
   "Move point to the head of this block.
 Jump from end to matching begin, from endcase to matching case, and so on."
@@ -6137,7 +6392,9 @@ Jump from end to matching begin, from endcase to matching 
case, and so on."
       (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" ))
      ((looking-at "\\<endclass\\>")
       ;; 5: Search back for matching class
-      (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" ))
+      (catch 'nesting
+        (verilog-leap-to-class-head)
+        (setq reg nil)))
      ((looking-at "\\<endtable\\>")
       ;; 6: Search back for matching table
       (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" ))
@@ -6175,7 +6432,19 @@ Jump from end to matching begin, from endcase to 
matching case, and so on."
       (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" ))
      ((looking-at "\\<endclocking\\>")
       ;; 12: Search back for matching clocking
-      (setq reg "\\(\\<clocking\\)\\|\\(\\<endclocking\\>\\)" )))
+      (setq reg "\\(\\<clocking\\)\\|\\(\\<endclocking\\>\\)" ))
+     ;; Search back for matching package
+     ((looking-at "\\<endpackage\\>")
+      (setq reg "\\(\\<package\\>\\)" ))
+     ;; Search back for matching program
+     ((looking-at "\\<endprogram\\>")
+      (setq reg "\\(\\<program\\>\\)" ))
+     ((looking-at "\\<`endif\\>")
+      ;; Search back for matching `endif `else `elsif
+      (setq reg "\\(\\<`ifn?def\\>\\)\\|\\(\\<`endif\\>\\)" ))
+     ((looking-at "\\<`else\\>")
+      ;; Search back for matching `else `else `elsif
+      (setq reg "\\(\\<`ifn?def\\>\\|\\<`elsif\\>\\)\\|\\(\\<`else\\>\\)" )))
     (if reg
        (catch 'skip
          (if (eq nesting 'yes)
@@ -6221,7 +6490,7 @@ Jump from end to matching begin, from endcase to matching 
case, and so on."
              (throw 'skip 1)))))))
 
 (defun verilog-continued-line ()
-  "Return true if this is a continued line.
+  "Return non-nil if this is a continued line.
 Set point to where line starts."
   (let ((continued 't))
     (if (eq 0 (forward-line -1))
@@ -6394,10 +6663,10 @@ Optional BOUND limits search."
            (let ((state (save-excursion (verilog-syntax-ppss))))
              (cond
                ((nth 7 state)  ; in // comment
-               (verilog-re-search-backward "//" nil 'move)
+               (re-search-backward "//" nil 'move)
                 (skip-chars-backward "/"))
                ((nth 4 state)  ; in /* */ comment
-               (verilog-re-search-backward "/\\*" nil 'move))))
+               (re-search-backward "/\\*" nil 'move))))
            (narrow-to-region bound (point))
            (while (/= here (point))
              (setq here (point))
@@ -6450,13 +6719,60 @@ Optional BOUND limits search."
              (if jump
                  (beginning-of-line 2))))))))
 
+(defun verilog-pos-at-beg-of-statement ()
+  "Return point position at the beginning of current statement."
+  (save-excursion
+    (verilog-beg-of-statement)
+    (point)))
+
+(defun verilog-col-at-beg-of-statement ()
+  "Return current column at the beginning of current statement."
+  (save-excursion
+    (verilog-beg-of-statement)
+    (current-column)))
+
+(defun verilog-pos-at-end-of-statement ()
+  "Return point position at the end of current statement."
+  (save-excursion
+    (verilog-end-of-statement)))
+
+(defun verilog-col-at-end-of-statement ()
+  "Return current column at the end of current statement."
+  (save-excursion
+    (verilog-end-of-statement)
+    (current-column)))
+
+(defun verilog-pos-at-forward-syntactic-ws ()
+  "Return point position at next non whitespace/comment token."
+  (save-excursion
+    (verilog-forward-syntactic-ws)
+    (point)))
+
+(defun verilog-col-at-forward-syntactic-ws ()
+  "Return current column at next non whitespace/comment token."
+  (save-excursion
+    (verilog-forward-syntactic-ws)
+    (current-column)))
+
+(defun verilog-pos-at-backward-syntactic-ws ()
+  "Return point position at previous non whitespace/comment token."
+  (save-excursion
+    (verilog-backward-syntactic-ws)
+    (point)))
+
+(defun verilog-col-at-backward-syntactic-ws ()
+  "Return current column at previous non whitespace/comment token."
+  (save-excursion
+    (verilog-backward-syntactic-ws)
+    (current-column)))
+
 (defun verilog-in-comment-p ()
-  "Return true if in a star or // comment."
+  "Return non-nil if in a star or // comment."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (or (nth 4 state) (nth 7 state))))
 
 (defun verilog-in-star-comment-p ()
-  "Return true if in a star comment."
+  "Return non-nil if in a star comment."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (and
      (nth 4 state)                     ; t if in a comment of style a // or b 
/**/
@@ -6465,40 +6781,39 @@ Optional BOUND limits search."
       ))))
 
 (defun verilog-in-slash-comment-p ()
-  "Return true if in a slash comment."
+  "Return non-nil if in a slash comment."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (nth 7 state)))
 
 (defun verilog-in-comment-or-string-p ()
-  "Return true if in a string or comment."
+  "Return non-nil if in a string or comment."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (or (nth 3 state) (nth 4 state) (nth 7 state)))) ; Inside string or 
comment)
 
 (defun verilog-in-attribute-p ()
-  "Return true if point is in an attribute (* [] attribute *)."
-  (save-match-data
-    (save-excursion
-      (verilog-re-search-backward "\\((\\*\\)\\|\\(\\*)\\)" nil 'move)
-      (cond
-       ((match-end 1)
-        (progn (goto-char (match-end 1))
-               (not (looking-at "\\s-*)")))
-        nil)
-       ((match-end 2)
-        (progn (goto-char (match-beginning 2))
-               (not (looking-at "(\\s-*")))
-        nil)
-       (t nil)))))
+  "Return non-nil if point is in an attribute (* [] attribute *)."
+  (let ((pos (point)))
+    (save-match-data
+      (save-excursion
+        (and (verilog-re-search-backward "(\\*" nil 'move)
+             (progn (forward-sexp)
+                    (skip-chars-backward "*)"))
+             (< pos (point)))))))
 
 (defun verilog-in-parameter-p ()
-  "Return true if point is in a parameter assignment #( p1=1, p2=5)."
+  "Return non-nil if point is in a parameter assignment #( p1=1, p2=5)."
   (save-match-data
     (save-excursion
-      (verilog-re-search-backward "\\(#(\\)\\|\\()\\)" nil 'move)
-      (numberp (match-beginning 1)))))
+      (and (progn
+             (verilog-backward-up-list 1)
+             (verilog-backward-syntactic-ws)
+             (= (preceding-char) ?\#))
+           (progn
+             (verilog-beg-of-statement-1)
+             (looking-at verilog-defun-re))))))
 
 (defun verilog-in-escaped-name-p ()
-  "Return true if in an escaped name."
+  "Return non-nil if in an escaped name."
   (save-excursion
     (backward-char)
     (skip-chars-backward "^ \t\n\f")
@@ -6507,20 +6822,20 @@ Optional BOUND limits search."
       nil)))
 
 (defun verilog-in-directive-p ()
-  "Return true if in a directive."
+  "Return non-nil if in a directive."
   (save-excursion
     (beginning-of-line)
     (looking-at verilog-directive-re-1)))
 
 (defun verilog-in-parenthesis-p ()
-  "Return true if in a ( ) expression (but not { } or [ ])."
+  "Return non-nil if in a ( ) expression (but not { } or [ ])."
   (save-match-data
     (save-excursion
       (verilog-re-search-backward "\\((\\)\\|\\()\\)" nil 'move)
       (numberp (match-beginning 1)))))
 
 (defun verilog-in-paren ()
-  "Return true if in a parenthetical expression.
+  "Return non-nil if in a parenthetical expression.
 May cache result using `verilog-syntax-ppss'."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (> (nth 0 state) 0 )))
@@ -6534,7 +6849,7 @@ May cache result using `verilog-syntax-ppss'."
       0 )))
 
 (defun verilog-in-paren-quick ()
-  "Return true if in a parenthetical expression.
+  "Return non-nil if in a parenthetical expression.
 Always starts from `point-min', to allow inserts with hooks disabled."
   ;; The -quick refers to its use alongside the other -quick functions,
   ;; not that it's likely to be faster than verilog-in-paren.
@@ -6542,7 +6857,7 @@ Always starts from `point-min', to allow inserts with 
hooks disabled."
     (> (nth 0 state) 0 )))
 
 (defun verilog-in-struct-p ()
-  "Return true if in a struct declaration."
+  "Return non-nil if in a struct declaration."
   (interactive)
   (save-excursion
     (if (verilog-in-paren)
@@ -6568,7 +6883,7 @@ Return >0 for nested struct."
         nil))))
 
 (defun verilog-in-coverage-p ()
-  "Return true if in a constraint or coverpoint expression."
+  "Return non-nil if in a constraint or coverpoint expression."
   (interactive)
   (save-excursion
     (if (verilog-in-paren)
@@ -6608,7 +6923,7 @@ Also move point to constraint."
                        (equal (char-before) ?\;)
                        (equal (char-before) ?\}))
                    ;; skip what looks like bus repetition operator {#{
-                   (not (string-match "^{\\s-*[()0-9a-zA-Z_\\]*\\s-*{"
+                   (not (string-match "^{\\s-*[][()0-9a-zA-Z_,:\\]*\\s-*{"
                                       (buffer-substring p (point)))))))))
       (progn
         (let ( (pt (point)) (pass 0))
@@ -6625,7 +6940,7 @@ Also move point to constraint."
                        ))
             ;; if first word token not keyword, it maybe the instance name
             ;;   check next word token
-            (if (looking-at "\\<\\w+\\>\\|\\s-*(\\s-*\\S-+")
+            (if (looking-at "\\<\\w+\\>\\|\\s-*[[(}]\\s-*\\S-+")
                 (progn (verilog-beg-of-statement)
                        (if (and
                             (not (string-match verilog-named-block-re 
(buffer-substring pt (point)))) ;; Abort if 'begin' keyword is found
@@ -6674,13 +6989,39 @@ Also move point to constraint."
        (verilog-in-struct-p)
        (looking-at "}\\(?:\\s-*\\w+\\s-*\\(?:,\\s-*\\w+\\s-*\\)*\\)?;")))
 
+(defun verilog-at-struct-decl-p ()
+  "Return non-nil if at a struct declaration."
+  (interactive)
+  (save-excursion
+    (verilog-re-search-forward "{" (point-at-eol) t)
+    (unless (bobp)
+      (backward-char))
+    (verilog-at-struct-p)))
+
+(defun verilog-at-enum-p ()
+  "If at the { of a enum, return true, not moving point."
+  (save-excursion
+    (when (equal (char-after) ?\{)
+      (verilog-beg-of-statement)
+      (beginning-of-line)
+      (when (verilog-re-search-forward verilog-typedef-enum-re 
(verilog-pos-at-end-of-statement) t)
+        t))))
+
+(defun verilog-at-enum-decl-p ()
+  "Return non-nil if at a enum declaration."
+  (interactive)
+  (save-excursion
+    (verilog-re-search-forward "{" (verilog-pos-at-end-of-statement) t)
+    (unless (bobp)
+      (backward-char))
+    (verilog-at-enum-p)))
+
 (defun verilog-parenthesis-depth ()
   "Return non zero if in parenthetical-expression."
   (save-excursion (nth 1 (verilog-syntax-ppss))))
 
-
 (defun verilog-skip-forward-comment-or-string ()
-  "Return true if in a string or comment."
+  "Return non-nil if in a string or comment."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (cond
      ((nth 3 state)                    ;Inside string
@@ -6695,7 +7036,7 @@ Also move point to constraint."
       nil))))
 
 (defun verilog-skip-backward-comment-or-string ()
-  "Return true if in a string or comment."
+  "Return non-nil if in a string or comment."
   (let ((state (save-excursion (verilog-syntax-ppss))))
     (cond
      ((nth 3 state)                    ;Inside string
@@ -6712,7 +7053,7 @@ Also move point to constraint."
       nil))))
 
 (defun verilog-skip-backward-comments ()
-  "Return true if a comment was skipped."
+  "Return non-nil if a comment was skipped."
   (let ((more t))
     (while more
       (setq more
@@ -6831,6 +7172,9 @@ Only look at a few lines to determine indent level."
   (let ((type (car indent-str))
        (ind (car (cdr indent-str))))
     (cond
+     (; handle indentation ignoring
+      (verilog-indent-ignore-p)
+      nil)
      (; handle continued exp
       (eq type 'cexp)
       (let ((here (point)))
@@ -6840,14 +7184,14 @@ Only look at a few lines to determine indent level."
           (= (preceding-char) ?\,)
           (save-excursion
             (verilog-beg-of-statement-1)
-            (looking-at verilog-declaration-re)))
+            (verilog-looking-at-decl-to-align)))
          (let* ( fst
                  (val
                   (save-excursion
                     (backward-char 1)
                     (verilog-beg-of-statement-1)
                     (setq fst (point))
-                    (if (looking-at verilog-declaration-re)
+                    (if (looking-at (verilog-get-declaration-re))
                          (progn  ; we have multiple words
                           (goto-char (match-end 0))
                           (skip-chars-forward " \t")
@@ -6869,9 +7213,9 @@ Only look at a few lines to determine indent level."
                         (+ (current-column) verilog-cexp-indent))))))
            (goto-char here)
            (indent-line-to val)
-           (if (and (not verilog-indent-lists)
-                    (verilog-in-paren))
-               (verilog-pretty-declarations-auto))
+            (when (and (not verilog-indent-lists)
+                       (verilog-in-paren))
+              (verilog-pretty-declarations-auto))
            ))
         ((= (preceding-char) ?\) )
          (goto-char here)
@@ -6897,21 +7241,17 @@ Only look at a few lines to determine indent level."
 
      (; handle inside parenthetical expressions
       (eq type 'cparenexp)
-      (let* ( here
-             (val (save-excursion
-                    (verilog-backward-up-list 1)
-                    (forward-char 1)
-                     (if verilog-indent-lists
-                         (skip-chars-forward " \t")
-                       (verilog-forward-syntactic-ws))
+      (let* ((val (verilog-cparenexp-indent-level))
+             (here (save-excursion
+                     (verilog-backward-up-list 1)
+                     (forward-char 1)
+                     (skip-chars-forward " \t")
+                     (point)))
+             (decl (save-excursion
+                     (goto-char here)
+                     (verilog-forward-syntactic-ws)
                      (setq here (point))
-                     (current-column)))
-
-             (decl (save-excursion
-                     (goto-char here)
-                     (verilog-forward-syntactic-ws)
-                     (setq here (point))
-                     (looking-at verilog-declaration-re))))
+                     (looking-at (verilog-get-declaration-re)))))
         (indent-line-to val)
         (if decl
             (verilog-pretty-declarations-auto))))
@@ -6938,17 +7278,20 @@ Only look at a few lines to determine indent level."
 
      (;-- defun
       (and (eq type 'defun)
-          (looking-at verilog-zero-indent-re))
+          (or (and verilog-indent-class-inside-pkg
+                    (looking-at verilog-zero-indent-no-class-re))
+               (and (not verilog-indent-class-inside-pkg)
+                    (looking-at verilog-zero-indent-re))))
       (indent-line-to 0))
 
      (;-- declaration
       (and (or
            (eq type 'defun)
            (eq type 'block))
-          (looking-at verilog-declaration-re)
+           (verilog-looking-at-decl-to-align)
            ;; Do not consider "virtual function", "virtual task", "virtual 
class"
            ;; as declarations
-           (not (looking-at (concat verilog-declaration-re
+           (not (looking-at (concat (verilog-get-declaration-re)
                                     "\\s-+\\(function\\|task\\|class\\)\\b"))))
       (verilog-indent-declaration ind))
 
@@ -6994,6 +7337,81 @@ Do not count named blocks or case-statements."
      (t
       (current-column)))))
 
+(defun verilog-cparenexp-indent-level ()
+  "Return indent level for current line inside a parenthetical expression."
+  (let ((start-pos (point))
+        (close-par (looking-at "[)}]"))
+        pos pos-arg-paren)
+    (save-excursion
+      (verilog-backward-up-list 1)
+      (if verilog-indent-lists
+          (progn
+            (forward-char 1)
+            (skip-chars-forward " \t")
+            (current-column))
+        ;; Indentation with `verilog-indent-lists' set to nil
+        (verilog-beg-of-statement-1)
+        (when (looking-at "\\<\\(function\\|task\\)\\>")
+          (verilog-beg-of-statement)) ; find virtual/protected/static
+        (cond (;; 1) Closing ); of a module/function/task
+               (and close-par
+                    (save-excursion
+                      (verilog-beg-of-statement-1)
+                      (or (looking-at verilog-complete-re)
+                          (progn (beginning-of-line)
+                                 (not (looking-at 
verilog-assignment-operation-re))))))
+               (current-column))
+              (;; 2) if (condition)
+               (looking-at "(")
+               (forward-char 1)
+               (skip-chars-forward " \t\f" (point-at-eol))
+               (current-column))
+              (;; 3) Inside a module/defun param list or function/task 
argument list
+               (or (looking-at verilog-defun-level-re)
+                   (looking-at 
"\\(\\<\\(virtual\\|protected\\|static\\)\\>\\s-+\\)?\\(\\<task\\>\\|\\<function\\>\\)"))
+               (setq pos-arg-paren (save-excursion
+                                     (goto-char start-pos)
+                                     (verilog-backward-up-list 1)
+                                     (forward-char)
+                                     (skip-chars-forward " \t")
+                                     (when (not (eolp))
+                                       (current-column))))
+               (or pos-arg-paren
+                   ;; arg in next line after (
+                   (+ (current-column) verilog-indent-level)))
+              (;; 4) Assignment operation
+               (save-excursion
+                 (beginning-of-line)
+                 (and (looking-at verilog-assignment-operation-re)
+                      (save-excursion
+                        (goto-char (match-beginning 2))
+                        (not (verilog-within-string)))
+                      (progn (verilog-forward-syntactic-ws)
+                             (not (looking-at verilog-complete-re)))))
+               (goto-char (match-end 2))
+               (skip-chars-forward " \t\f" (point-at-eol))
+               (skip-chars-forward "{(" (1+ (point)))
+               (skip-chars-forward " \t\f" (point-at-eol))
+               (current-column))
+              (;; 5) Typedef enum declaration
+               (verilog-at-enum-decl-p)
+               (verilog-re-search-forward "{" 
(verilog-pos-at-end-of-statement) t)
+               (if (> (verilog-pos-at-forward-syntactic-ws) (point-at-eol))
+                   (+ (verilog-col-at-beg-of-statement) verilog-indent-level)
+                 (verilog-col-at-forward-syntactic-ws)))
+              (;; 6) Long reporting strings (e.g. $display or $sformatf inside 
`uvm_info)
+               (save-excursion
+                 (goto-char start-pos)
+                 (verilog-backward-up-list 1)
+                 (setq pos (1+ (point)))
+                 (backward-word)
+                 (or (looking-at (concat "\\$" verilog-identifier-re)) ; 
System function/task
+                     (looking-at verilog-uvm-statement-re)))         ; `uvm_* 
macros
+               (goto-char pos)
+               (current-column))
+              (t ;; 7) Default
+               (+ (current-column) verilog-indent-level)))))))
+
 (defun verilog-indent-comment ()
   "Indent current line as comment."
   (let* ((stcol
@@ -7053,90 +7471,137 @@ _ARG is ignored, for `comment-indent-function' 
compatibility."
 
 ;;
 
+(defun verilog-align-comments (startpos endpos)
+  "Align inline comments between STARTPOS and ENDPOS."
+  (let (comm-ind e)
+    (when verilog-align-decl-expr-comments
+      (setq comm-ind (verilog-get-comment-align-indent (marker-position 
startpos) endpos))
+      (save-excursion
+        (goto-char (marker-position startpos))
+        (while (progn (setq e (marker-position endpos))
+                      (< (point) e))
+          (when (verilog-search-comment-in-declaration e)
+            (goto-char (match-beginning 0))
+            (delete-horizontal-space)
+            (indent-to (1- (+ comm-ind verilog-align-comment-distance)))))))))
+
 (defun verilog-pretty-declarations-auto (&optional quiet)
   "Call `verilog-pretty-declarations' QUIET based on `verilog-auto-lineup'."
   (when (or (eq 'all verilog-auto-lineup)
            (eq 'declarations verilog-auto-lineup))
     (verilog-pretty-declarations quiet)))
 
+(defun verilog--pretty-declarations-find-end (&optional reg-end)
+  "Find end position for current alignment of declarations.
+If region is active, use arg REG-END to set a limit on the alignment."
+  (let (e)
+    (if (and (verilog-parenthesis-depth)
+             (not (verilog-in-struct-p)))
+        ;; In an argument list or parameter block
+        (progn
+          (verilog-backward-up-list -1)
+          (forward-char -1)
+          (verilog-backward-syntactic-ws)
+          (if (region-active-p)
+              (min reg-end (point))
+            (point)))
+      ;; In a declaration block (not in argument list)
+      (verilog-end-of-statement)
+      (setq e (point)) ; Might be on last line
+      (verilog-forward-syntactic-ws)
+      (while (verilog-looking-at-decl-to-align)
+        (verilog-end-of-statement)
+        (setq e (point))
+        (verilog-forward-syntactic-ws))
+      (if (region-active-p)
+          (min reg-end e)
+        e))))
+
+(defun verilog--pretty-declarations-find-base-ind ()
+  "Find base indentation for current alignment of declarations."
+  (if (and (verilog-parenthesis-depth)
+           (not (verilog-in-struct-p)))
+      ;; In an argument list or parameter block
+      (progn
+        (unless (or (verilog-looking-back "(" (point-at-bol))
+                    (bolp))
+          (forward-char 1))
+       (skip-chars-forward " \t")
+       (current-column))
+    ;; In a declaration block (not in argument list)
+    (progn
+      (verilog-do-indent (verilog-calculate-indent))
+      (verilog-forward-ws&directives)
+      (current-column))))
+
 (defun verilog-pretty-declarations (&optional quiet)
   "Line up declarations around point.
 Be verbose about progress unless optional QUIET set."
   (interactive)
-  (let* ((m1 (make-marker))
-         (e (point))
-        el
-         r
-        (here (point))
-         ind
-         start
-         startpos
-         end
-         endpos
-         base-ind
-         )
+  (let ((m1 (make-marker))
+        (e (point))
+       (here (point))
+       el r ind start startpos end endpos base-ind rstart rend)
     (save-excursion
+      (when (region-active-p)
+        (setq rstart (region-beginning))
+        (setq rend (region-end))
+        (goto-char rstart)) ; Shrinks the region but ensures that start is a 
valid declaration
       (if (progn
-            ;; (verilog-beg-of-statement-1)
+            ;; Check if alignment can be performed
             (beginning-of-line)
             (verilog-forward-syntactic-ws)
-            (and (not (verilog-in-directive-p))  ; could have `define input foo
-                 (looking-at verilog-declaration-re)))
-         (progn
-           (if (verilog-parenthesis-depth)
-               ;; in an argument list or parameter block
-               (setq el (verilog-backward-up-list -1)
-                     start (progn
-                             (goto-char e)
-                             (verilog-backward-up-list 1)
-                              (forward-line)  ; ignore ( input foo,
-                             (verilog-re-search-forward verilog-declaration-re 
el 'move)
-                             (goto-char (match-beginning 0))
+            (or (and (not (verilog-in-directive-p))  ; could have `define 
input foo
+                     (verilog-looking-at-decl-to-align))
+                (and (verilog-parenthesis-depth)
+                     (looking-at verilog-interface-modport-re))))
+          ;; Find boundaries of alignment
+          (progn
+            (cond (;; Using region
+                   (region-active-p)
+                   (setq start rstart
+                         startpos (set-marker (make-marker) start)
+                         end (progn (goto-char start)
+                                    (verilog--pretty-declarations-find-end 
rend))
+                         endpos (set-marker (make-marker) end)
+                         base-ind (progn (goto-char start)
+                                         
(verilog--pretty-declarations-find-base-ind))))
+                  (;; In an argument list or parameter block
+                   (and (verilog-parenthesis-depth)
+                        (not (verilog-in-struct-p)))
+                   (setq el (verilog-backward-up-list -1)
+                        start (progn
+                                (goto-char e)
+                                (verilog-backward-up-list 1)
+                                (verilog-re-search-forward 
(verilog-get-declaration-re 'iface-mp) el 'move)
+                                (goto-char (match-beginning 0))
+                                (skip-chars-backward " \t")
+                                (point))
+                        startpos (set-marker (make-marker) start)
+                        end (progn (goto-char start)
+                                    (verilog--pretty-declarations-find-end))
+                        endpos (set-marker (make-marker) end)
+                        base-ind (progn (goto-char start)
+                                         
(verilog--pretty-declarations-find-base-ind))))
+                  (;; In a declaration block (not in argument list)
+                   t
+                   (setq
+                   start (progn
+                           (verilog-beg-of-statement-1)
+                           (while (and (verilog-looking-at-decl-to-align)
+                                       (not (bobp)))
                              (skip-chars-backward " \t")
-                             (point))
-                     startpos (set-marker (make-marker) start)
-                     end (progn
-                           (goto-char start)
-                           (verilog-backward-up-list -1)
-                           (forward-char -1)
-                           (verilog-backward-syntactic-ws)
-                           (point))
-                     endpos (set-marker (make-marker) end)
-                     base-ind (progn
-                                (goto-char start)
-                                (forward-char 1)
-                                (skip-chars-forward " \t")
-                                (current-column)))
-             ;; in a declaration block (not in argument list)
-             (setq
-              start (progn
-                      (verilog-beg-of-statement-1)
-                      (while (and (looking-at verilog-declaration-re)
-                                  (not (bobp)))
-                        (skip-chars-backward " \t")
-                        (setq e (point))
-                        (beginning-of-line)
-                        (verilog-backward-syntactic-ws)
-                        (backward-char)
-                        (verilog-beg-of-statement-1))
-                      e)
-              startpos (set-marker (make-marker) start)
-              end (progn
-                    (goto-char here)
-                    (verilog-end-of-statement)
-                    (setq e (point))   ;Might be on last line
-                    (verilog-forward-syntactic-ws)
-                    (while (looking-at verilog-declaration-re)
-                      (verilog-end-of-statement)
-                      (setq e (point))
-                      (verilog-forward-syntactic-ws))
-                    e)
-              endpos (set-marker (make-marker) end)
-              base-ind (progn
-                         (goto-char start)
-                         (verilog-do-indent (verilog-calculate-indent))
-                         (verilog-forward-ws&directives)
-                         (current-column))))
+                             (setq e (point))
+                             (verilog-backward-syntactic-ws)
+                             (backward-char)
+                             (verilog-beg-of-statement-1))
+                           e)
+                   startpos (set-marker (make-marker) start)
+                   end (progn (goto-char here)
+                               (verilog--pretty-declarations-find-end))
+                   endpos (set-marker (make-marker) end)
+                   base-ind (progn (goto-char start)
+                                    
(verilog--pretty-declarations-find-base-ind)))))
            ;; OK, start and end are set
            (goto-char (marker-position startpos))
            (if (and (not quiet)
@@ -7152,12 +7617,13 @@ Be verbose about progress unless optional QUIET set."
                 (indent-line-to base-ind)
                 (verilog-forward-ws&directives)
                 (if (< (point) e)
-                    (verilog-re-search-forward "[ \t\n\f]" e 'move)))
+                    (verilog-re-search-forward "[ \t\n\f]" (marker-position 
endpos) 'move)))
               (t
-               (just-one-space)
-               (verilog-re-search-forward "[ \t\n\f]" e 'move)))
-             ;;(forward-line)
-             )
+                (unless (verilog-looking-back "(" (point-at-bol))
+                  (just-one-space))
+                (if (looking-at verilog-comment-start-regexp)
+                    (verilog-forward-syntactic-ws)
+                 (verilog-re-search-forward "[ \t\n\f]" e 'move)))))
            ;; Now find biggest prefix
            (setq ind (verilog-get-lineup-indent (marker-position startpos) 
endpos))
            ;; Now indent each line.
@@ -7167,27 +7633,27 @@ Be verbose about progress unless optional QUIET set."
                          (> r 0))
              (setq e (point))
              (unless quiet (message "%d" r))
-              ;; (verilog-do-indent (verilog-calculate-indent)))
              (verilog-forward-ws&directives)
              (cond
-              ((or (and verilog-indent-declaration-macros
-                        (looking-at verilog-declaration-re-2-macro))
-                   (looking-at verilog-declaration-re-2-no-macro))
-               (let ((p (match-end 0)))
-                 (set-marker m1 p)
-                 (if (verilog-re-search-forward "[[#`]" p 'move)
-                     (progn
-                       (forward-char -1)
-                       (just-one-space)
-                       (goto-char (marker-position m1))
+              ((looking-at (verilog-get-declaration-re 'iface-mp))
+                (unless (looking-at (verilog-get-declaration-re 
'embedded-comments))
+                  (let ((p (match-end 0)))
+                    (set-marker m1 p)
+                    (if (verilog-re-search-forward "[[#`]" p 'move)
+                        (progn
+                          (forward-char -1)
+                          (just-one-space)
+                          (goto-char (marker-position m1))
+                          (delete-horizontal-space)
+                          (indent-to ind 1))
+                      (progn
                         (delete-horizontal-space)
-                        (indent-to ind 1))
-                   (progn
-                      (delete-horizontal-space)
-                      (indent-to ind 1)))))
+                        (indent-to ind 1))))))
               ((verilog-continued-line-1 (marker-position startpos))
                (goto-char e)
-               (indent-line-to ind))
+                (unless (and (verilog-in-parenthesis-p)
+                             (looking-at (concat "\\s-*" 
verilog-identifier-sym-re "\\s-+" verilog-identifier-sym-re "\\s-*")))
+                  (indent-line-to ind)))
               ((verilog-in-struct-p)
                ;; could have a declaration of a user defined item
                (goto-char e)
@@ -7197,104 +7663,202 @@ Be verbose about progress unless optional QUIET set."
                (verilog-forward-ws&directives)
                (forward-line -1)))
              (forward-line 1))
-           (unless quiet (message "")))))))
+            ;; Align comments if enabled
+            (when verilog-align-decl-expr-comments
+              (verilog-align-comments startpos endpos)))
+        ;; Exit
+       (unless quiet (message ""))))))
+
+(defun verilog--pretty-expr-assignment-found (&optional discard-re)
+  "Return non-nil if point is at a valid assignment operation to be aligned.
+Ensure cursor is not over DISCARD-RE (e.g. Verilog keywords).
+If returned non-nil, update match data according to 
`verilog-assignment-operation-re'."
+  ;; Not looking at a verilog keyword sentence (i.e looking at a potential 
assignment)
+  (and (if discard-re
+           (not (looking-at discard-re))
+         t)
+       ;; Corner case to filter first parameter on param lists
+       (save-excursion
+         (if (and (verilog-re-search-forward verilog-assignment-operation-re 
(point-at-eol) 'move)
+                  (verilog-in-parenthesis-p))
+             (progn (verilog-backward-up-list 1)
+                    (forward-char 1)
+                    (not (eq 0 (string-match discard-re 
(buffer-substring-no-properties (point) (point-at-eol))))))
+           t))
+       ;; Don't work on multiline assignments unless they are continued lines
+       ;; e.g, multiple parameters or variable declarations in the same 
statement
+       (if (save-excursion
+             (and (not (verilog-in-parameter-p))
+                  (verilog-continued-line)
+                  (not (looking-at verilog-basic-complete-re))))
+           (save-excursion
+             (verilog-beg-of-statement-1)
+             (looking-at (verilog-get-declaration-re)))
+         t)
+       ;; Ensure it's not any kind of logical comparison
+       (save-excursion
+         (unless (and (not (verilog-in-parameter-p))
+                      (verilog-re-search-forward (verilog-regexp-words '("if" 
"for" "assert" "with")) (point-at-eol) 'move))
+           t))
+       ;; Looking at an assignment (last check, provides match data)
+       (looking-at verilog-assignment-operation-re)))
+
+(defun verilog--pretty-expr-find-end (&optional discard-re reg-end)
+  "Find end position for current alignment of expressions.
+Use optional arg DISCARD-RE when aligning expressions outside of an
+argument list and REG-END to set a limit on the alignment when the
+region is active."
+  (if (verilog-in-parenthesis-p)
+      ;; Limit end in argument list
+      (progn
+        (verilog-backward-up-list -1)
+        (forward-char -1)
+        (verilog-backward-syntactic-ws)
+        (if (region-active-p)
+            (min reg-end (point))
+          (point)))
+    ;; Limit end in non-argument list
+    (save-excursion ; EOL of the last line of the assignment block
+      (end-of-line)
+      (let ((pt (point))) ; Might be on last line
+        (verilog-forward-syntactic-ws)
+        (beginning-of-line)
+        (while (and (verilog--pretty-expr-assignment-found discard-re)
+                    (progn
+                      (end-of-line)
+                      (not (eq pt (point)))))
+          (setq pt (point))
+          (verilog-forward-syntactic-ws)
+          (beginning-of-line))
+        (if (region-active-p)
+            (min reg-end pt)
+          pt)))))
 
 (defun verilog-pretty-expr (&optional quiet)
   "Line up expressions around point.
 If QUIET is non-nil, do not print messages showing the progress of line-up."
   (interactive)
-  (unless (verilog-in-comment-or-string-p)
+  (let* ((basic-complete-pretty-expr-re (if verilog-align-assign-expr
+                                            
verilog-basic-complete-expr-no-assign-re
+                                          verilog-basic-complete-expr-re))
+         (complete-pretty-expr-re (concat verilog-extended-complete-re 
"\\|\\(" basic-complete-pretty-expr-re "\\)"))
+         (discard-re (concat "^\\s-*\\(" complete-pretty-expr-re "\\)"))
+         rstart rend)
     (save-excursion
-      (let ((regexp (concat "^\\s-*" verilog-complete-reg))
-            (regexp1 (concat "^\\s-*" verilog-basic-complete-re)))
+      (when (region-active-p)
+        (setq rstart (region-beginning))
+        (setq rend (region-end))
+        (goto-char rstart))
+      (unless (verilog-in-comment-or-string-p)
         (beginning-of-line)
-        (when (and (not (looking-at regexp))
-                   (looking-at verilog-assignment-operation-re)
+        (when (and (verilog--pretty-expr-assignment-found discard-re)
                    (save-excursion
                      (goto-char (match-end 2))
                      (and (not (verilog-in-attribute-p))
-                          (not (verilog-in-parameter-p))
                           (not (verilog-in-comment-or-string-p)))))
-          (let* ((start (save-excursion ; BOL of the first line of the 
assignment block
-                          (beginning-of-line)
-                          (let ((pt (point)))
-                            (verilog-backward-syntactic-ws)
-                            (beginning-of-line)
-                            (while (and (not (looking-at regexp1))
-                                        (looking-at 
verilog-assignment-operation-re)
-                                        (not (bobp)))
-                              (setq pt (point))
-                              (verilog-backward-syntactic-ws)
-                              (beginning-of-line)) ; Ack, need to grok `define
-                            pt)))
-                 (end (save-excursion ; EOL of the last line of the assignment 
block
-                        (end-of-line)
-                        (let ((pt (point))) ; Might be on last line
-                          (verilog-forward-syntactic-ws)
-                          (beginning-of-line)
-                          (while (and
-                                  (not (looking-at regexp1))
-                                  (looking-at verilog-assignment-operation-re)
-                                  (progn
-                                    (end-of-line)
-                                    (not (eq pt (point)))))
-                            (setq pt (point))
-                            (verilog-forward-syntactic-ws)
-                            (beginning-of-line))
-                          pt)))
-                 (contains-2-char-operator (string-match "<=" 
(buffer-substring-no-properties start end)))
-                 (endmark (set-marker (make-marker) end)))
-            (goto-char start)
-            (verilog-do-indent (verilog-calculate-indent))
+          (let* ((start (cond (;; Using region
+                               (region-active-p)
+                               rstart)
+                              (;; Parameter list
+                               (verilog-in-parenthesis-p)
+                               (progn
+                                 (verilog-backward-up-list 1)
+                                 (forward-char)
+                                 (verilog-re-search-forward 
verilog-assignment-operation-re-2 nil 'move)
+                                 (goto-char (match-beginning 0))
+                                 (point)))
+                              (t ;; Declarations
+                               (save-excursion ; BOL of the first line of the 
assignment block
+                                 (beginning-of-line)
+                                 (let ((pt (point)))
+                                   (verilog-backward-syntactic-ws)
+                                   (beginning-of-line)
+                                   (while (and 
(verilog--pretty-expr-assignment-found discard-re)
+                                               (not (bobp)))
+                                     (setq pt (point))
+                                     (verilog-backward-syntactic-ws)
+                                     (beginning-of-line)) ; Ack, need to grok 
`define
+                                   pt)))))
+                 (startpos (set-marker (make-marker) start))
+                 (end (cond (;; Using region
+                             (region-active-p)
+                             (verilog--pretty-expr-find-end discard-re rend))
+                            (;; Parameter list
+                             (verilog-in-parenthesis-p)
+                             (verilog--pretty-expr-find-end))
+                            (t ;; Declarations
+                             (verilog--pretty-expr-find-end discard-re))))
+                (endpos (set-marker (make-marker) end))
+                 (contains-2-char-operator (string-match "<=" 
(buffer-substring-no-properties start end))))
+            ;; Start with alignment
+            (goto-char startpos)
+            (unless (save-excursion
+                      (beginning-of-line)
+                      (looking-at discard-re))
+              (verilog-do-indent (verilog-calculate-indent)))
             (when (and (not quiet)
-                       (> (- end start) 100))
+                       (> (- (marker-position endpos) (marker-position 
startpos)) 100))
               (message "Lining up expressions.. (please stand by)"))
-
             ;; Set indent to minimum throughout region
             ;; Rely on mark rather than on point as the indentation changes can
             ;; make the older point reference obsolete
-            (while (< (point) (marker-position endmark))
+            (while (< (point) (marker-position endpos))
               (beginning-of-line)
               (save-excursion
-                (verilog-just-one-space verilog-assignment-operation-re))
+                (if (looking-at verilog-complete-re)
+                    (progn (goto-char (marker-position startpos))
+                           (verilog-just-one-space 
verilog-assignment-operation-re-2))
+                  (verilog-just-one-space verilog-assignment-operation-re)))
               (verilog-do-indent (verilog-calculate-indent))
               (end-of-line)
               (verilog-forward-syntactic-ws))
 
-            (let ((ind (verilog-get-lineup-indent-2 
verilog-assignment-operation-re start (marker-position endmark))) ; Find the 
biggest prefix
+            (let ((ind (verilog-get-lineup-indent-2 
verilog-assignment-operation-re (marker-position startpos) (marker-position 
endpos))) ; Find the biggest prefix
                   e)
               ;; Now indent each line.
-              (goto-char start)
+              (goto-char (marker-position startpos))
               (while (progn
-                       (setq e (marker-position endmark))
+                       (setq e (marker-position endpos))
                        (> e (point)))
                 (unless quiet
                   (message " verilog-pretty-expr: %d" (- e (point))))
                 (setq e (point))
                 (cond
-                 ((looking-at verilog-assignment-operation-re)
+                 ((or (looking-at verilog-assignment-operation-re)
+                      (and (verilog-in-parenthesis-p)
+                           (looking-at verilog-assignment-operation-re-2)))
                   (goto-char (match-beginning 2))
-                  (unless (or (verilog-in-parenthesis-p) ; Leave attributes 
and comparisons alone
+                  (unless (or (and (verilog-in-parenthesis-p) ; Leave 
attributes and comparisons alone
+                                   (save-excursion ; Allow alignment of some 
expressions inside param/port list
+                                     (verilog-backward-up-list 1)
+                                     (verilog-beg-of-statement-1)
+                                     (not (looking-at 
verilog-defun-level-re))))
                               (verilog-in-coverage-p))
                     (if (and contains-2-char-operator
                              (eq (char-after) ?=))
                         (indent-to (1+ ind)) ; Line up the = of the <= with 
surrounding =
-                      (indent-to ind))))
-                 ((verilog-continued-line-1 start)
+                      (indent-to ind)))
+                  (forward-line 1))
+                 ((and (save-excursion
+                         (verilog-forward-syntactic-ws)
+                         (not (looking-at verilog-complete-re)))
+                       (verilog-continued-line-1 (marker-position startpos)))
                   (goto-char e)
-                  (indent-line-to ind))
-                 (t                     ; Must be comment or white space
+                  (indent-line-to ind)
+                  (forward-line 1))
+                 (t ; Must be comment, white space or syntax error
                   (goto-char e)
-                  (verilog-forward-ws&directives)
-                  (forward-line -1)))
-                (forward-line 1))
+                  (forward-line 1))))
+              ;; Align comments if enabled
+              (when verilog-align-decl-expr-comments
+                (verilog-align-comments startpos endpos))
               (unless quiet
                 (message "")))))))))
 
 (defun verilog-just-one-space (myre)
   "Remove extra spaces around regular expression MYRE."
   (interactive)
-  (if (and (not(looking-at verilog-complete-reg))
+  (if (and (not(looking-at verilog-complete-re))
           (looking-at myre))
       (let ((p1 (match-end 1))
            (p2 (match-end 2)))
@@ -7312,59 +7876,63 @@ BASEIND is the base indent to offset everything."
   ;; `ind' is used in expressions stored in `verilog-indent-alist'.
   (verilog--suppressed-warnings ((lexical ind)) (defvar ind))
   (let ((pos (point-marker))
-       (lim (save-excursion
-              ;; (verilog-re-search-backward verilog-declaration-opener nil 
'move)
-              (verilog-re-search-backward 
"\\(\\<begin\\>\\)\\|\\(\\<\\(connect\\)?module\\>\\)\\|\\(\\<task\\>\\)" nil 
'move)
-              (point)))
-       (ind)
-       (val)
-       (m1 (make-marker)))
-    (setq val
-         (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist)))))
+        (m1 (make-marker))
+        (in-paren (verilog-parenthesis-depth))
+        (val (+ baseind (eval (cdr (assoc 'declaration 
verilog-indent-alist)))))
+        ind)
     (indent-line-to val)
-
     ;; Use previous declaration (in this module) as template.
-    (if (or (eq 'all verilog-auto-lineup)
-           (eq 'declarations verilog-auto-lineup))
-       (if (verilog-re-search-backward
-            (or (and verilog-indent-declaration-macros
-                     verilog-declaration-re-1-macro)
-                verilog-declaration-re-1-no-macro)
-            lim t)
-           (progn
-             (goto-char (match-end 0))
-             (skip-chars-forward " \t")
-             (setq ind (current-column))
-             (goto-char pos)
-             (setq val
-                   (+ baseind
-                      (eval (cdr (assoc 'declaration verilog-indent-alist)))))
-             (indent-line-to val)
-             (if (and verilog-indent-declaration-macros
-                      (looking-at verilog-declaration-re-2-macro))
-                 (let ((p (match-end 0)))
-                   (set-marker m1 p)
-                   (if (verilog-re-search-forward "[[#`]" p 'move)
-                       (progn
-                         (forward-char -1)
-                         (just-one-space)
-                         (goto-char (marker-position m1))
-                          (delete-horizontal-space)
-                          (indent-to ind 1))
-                      (delete-horizontal-space)
-                      (indent-to ind 1)))
-               (if (looking-at verilog-declaration-re-2-no-macro)
-                   (let ((p (match-end 0)))
-                     (set-marker m1 p)
-                     (if (verilog-re-search-forward "[[`#]" p 'move)
-                         (progn
-                           (forward-char -1)
-                           (just-one-space)
-                           (goto-char (marker-position m1))
-                            (delete-horizontal-space)
-                            (indent-to ind 1))
-                        (delete-horizontal-space)
-                        (indent-to ind 1))))))))
+    (when (and (or (eq 'all verilog-auto-lineup)
+                   (eq 'declarations verilog-auto-lineup))
+               ;; Limit alignment to consecutive statements
+               (progn
+                 (verilog-backward-syntactic-ws)
+                 (backward-char)
+                 (looking-at ";"))
+               (progn
+                 (verilog-beg-of-statement)
+                 (looking-at (verilog-get-declaration-re)))
+               ;; Make sure that we don't jump to an argument list or 
parameter block if
+               ;; we were in a declaration block (not in argument list)
+               (or (and in-paren
+                        (verilog-parenthesis-depth))
+                   (and (not in-paren)
+                        (not (verilog-parenthesis-depth))))
+               ;; Skip variable declarations inside functions/tasks
+               (skip-chars-backward " \t\f")
+               (bolp))
+      (goto-char (match-end 0))
+      (skip-chars-forward " \t")
+      (setq ind (current-column))
+      (goto-char pos)
+      (setq val
+            (+ baseind
+               (eval (cdr (assoc 'declaration verilog-indent-alist)))))
+      (indent-line-to val)
+      (if (looking-at (verilog-get-declaration-re))
+          (let ((p (match-end 0)))
+            (set-marker m1 p)
+            (if (verilog-re-search-forward "[[#`]" p 'move)
+                (progn
+                  (forward-char -1)
+                  (just-one-space)
+                  (goto-char (marker-position m1))
+                  (delete-horizontal-space)
+                  (indent-to ind 1))
+              (delete-horizontal-space)
+              (indent-to ind 1)))
+        (when (looking-at (verilog-get-declaration-re))
+          (let ((p (match-end 0)))
+            (set-marker m1 p)
+            (if (verilog-re-search-forward "[[`#]" p 'move)
+                (progn
+                  (forward-char -1)
+                  (just-one-space)
+                  (goto-char (marker-position m1))
+                  (delete-horizontal-space)
+                  (indent-to ind 1))
+              (delete-horizontal-space)
+              (indent-to ind 1))))))
     (goto-char pos)))
 
 (defun verilog-get-lineup-indent (b edpos)
@@ -7376,16 +7944,13 @@ Region is defined by B and EDPOS."
       ;; Get rightmost position
       (while (progn (setq e (marker-position edpos))
                    (< (point) e))
-       (if (verilog-re-search-forward
-            (or (and verilog-indent-declaration-macros
-                     verilog-declaration-re-1-macro)
-                verilog-declaration-re-1-no-macro) e 'move)
-           (progn
-             (goto-char (match-end 0))
-             (verilog-backward-syntactic-ws)
-             (if (> (current-column) ind)
-                 (setq ind (current-column)))
-             (goto-char (match-end 0)))))
+       (when (verilog-re-search-forward (verilog-get-declaration-re 'iface-mp) 
e 'move)
+         (goto-char (match-end 0))
+         (verilog-backward-syntactic-ws)
+         (if (> (current-column) ind)
+             (setq ind (current-column)))
+          (goto-char (match-end 0))
+          (forward-line 1)))
       (if (> ind 0)
          (1+ ind)
        ;; No lineup-string found
@@ -7402,12 +7967,13 @@ BEG and END."
   (save-excursion
     (let ((ind 0))
       (goto-char beg)
+      (beginning-of-line)
       ;; Get rightmost position
       (while (< (point) end)
        (when (and (verilog-re-search-forward regexp end 'move)
                    (not (verilog-in-attribute-p))) ; skip attribute exprs
          (goto-char (match-beginning 2))
-         (verilog-backward-syntactic-ws)
+          (skip-chars-backward " \t")
          (if (> (current-column) ind)
              (setq ind (current-column)))
          (goto-char (match-end 0))))
@@ -7420,6 +7986,32 @@ BEG and END."
                  (1+ (current-column))))
       ind)))
 
+(defun verilog-search-comment-in-declaration (bound)
+  "Move cursor to position of comment in declaration and return point.
+BOUND is a buffer position that bounds the search."
+  (and (verilog-re-search-forward (verilog-get-declaration-re 'iface-mp) bound 
'move)
+       (not (looking-at (concat "\\s-*" verilog-comment-start-regexp)))
+       (re-search-forward verilog-comment-start-regexp (point-at-eol) 
:noerror)))
+
+(defun verilog-get-comment-align-indent (b endpos)
+  "Return the indent level that will line up comments within the region.
+Region is defined by B and ENDPOS."
+  (save-excursion
+    (let ((ind 0)
+          e comm-ind)
+      (goto-char b)
+      ;; Get rightmost position
+      (while (progn (setq e (marker-position endpos))
+                    (< (point) e))
+        (when (verilog-search-comment-in-declaration e)
+          (end-of-line)
+          (verilog-backward-syntactic-ws)
+          (setq comm-ind (1+ (current-column)))
+          (when (> comm-ind ind)
+            (setq ind comm-ind)))
+        (forward-line 1))
+      ind)))
+
 (defun verilog-comment-depth (type val)
   "A useful mode debugging aide.  TYPE and VAL are comments for insertion."
   (save-excursion
@@ -7439,6 +8031,19 @@ BEG and END."
     (insert
      (format "%s %d" type val))))
 
+(defun verilog-indent-ignore-p ()
+  "Return non-nil if current line should ignore indentation."
+  (or (and verilog-indent-ignore-multiline-defines
+           ;; Line with multiline define, ends with "\" or "\" plus trailing 
whitespace
+           (or (looking-at ".*\\\\\\s-*$")
+               (save-excursion  ; Last line after multiline define
+                 (verilog-backward-syntactic-ws)
+                 (unless (bobp)
+                   (backward-char))
+                 (looking-at "\\\\"))))
+      (and verilog-indent-ignore-regexp ; Ignore lines according to specified 
regexp
+           (looking-at verilog-indent-ignore-regexp))))
+
 
 ;;; Completion:
 ;;
@@ -7446,7 +8051,7 @@ BEG and END."
 (defvar verilog-all nil)
 (defvar verilog-buffer-to-use nil)
 (defvar verilog-toggle-completions nil
-  "True means \\<verilog-mode-map>\\[verilog-complete-word] should try all 
possible completions one by one.
+  "Non-nil means \\<verilog-mode-map>\\[verilog-complete-word] should try all 
possible completions one by one.
 Repeated use of \\[verilog-complete-word] will show you all of them.
 Normally, when there is more than one possible completion,
 it displays a list of all possible completions.")
@@ -7598,16 +8203,14 @@ TYPE is `module', `tf' for task or function, or t if 
unknown."
 (defun verilog-get-completion-decl (end)
   "Macro for searching through current declaration (var, type or const)
 for matches of `str' and adding the occurrence tp `all' through point END."
-  (let ((re (or (and verilog-indent-declaration-macros
-                    verilog-declaration-re-2-macro)
-               verilog-declaration-re-2-no-macro))
+  (let ((re (verilog-get-declaration-re))
        decl-end match)
     ;; Traverse lines
     (while (and (< (point) end)
                (verilog-re-search-forward re end t))
       ;; Traverse current line
       (setq decl-end (save-excursion (verilog-declaration-end)))
-      (while (and (verilog-re-search-forward verilog-symbol-re decl-end t)
+      (while (and (verilog-re-search-forward verilog-identifier-sym-re 
decl-end t)
                  (not (match-end 1)))
        (setq match (buffer-substring (match-beginning 0) (match-end 0)))
        (if (string-match (concat "\\<" verilog-str) match)
@@ -7619,7 +8222,7 @@ for matches of `str' and adding the occurrence tp `all' 
through point END."
   "Calculate all possible completions for variables (or constants)."
   (let ((start (point)))
     ;; Search for all reachable var declarations
-    (verilog-beg-of-defun)
+    (verilog-re-search-backward verilog-defun-re nil 'move)
     (save-excursion
       ;; Check var declarations
       (verilog-get-completion-decl start))))
@@ -8765,6 +9368,11 @@ Return an array of [outputs inouts inputs wire reg 
assign const gparam intf]."
                 (t  ; Bit width
                 (setq vec (verilog-string-replace-matches
                            "\\s-+" "" nil nil keywd)))))
+         ;; int'(a) is cast, not declaration of a
+         ((and (looking-at "'")
+               (not rvalue))
+          (forward-char 1)
+          (setq expect-signal nil rvalue nil))
         ;; Normal or escaped identifier -- note we remember the \ if escaped
         ((looking-at "\\s-*\\([a-zA-Z0-9`_$]+\\|\\\\[^ \t\n\f]+\\)")
          (goto-char (match-end 0))
@@ -9702,9 +10310,9 @@ resolve it.  If optional RECURSE is non-nil, recurse 
through \\=`includes.
 Localparams must be simple assignments to constants, or have their own
 \"localparam\" label rather than a list of localparams.  Thus:
 
-    localparam X = 5, Y = 10;  // Ok
-    localparam X = {1\\='b1, 2\\='h2}; // Ok
-    localparam X = {1\\='b1, 2\\='h2}, Y = 10; // Bad, make into 2 localparam 
lines
+    localparam X = 5, Y = 10;   // Ok
+    localparam X = {1\\='b1, 2\\='h2};  // Ok
+    localparam X = {1\\='b1, 2\\='h2}, Y = 10;  // Bad, make into 2 localparam 
lines
 
 Defines must be simple text substitutions, one on a line, starting
 at the beginning of the line.  Any ifdefs or multiline comments around the
@@ -9827,8 +10435,7 @@ variable over and over when many modules are compiled 
together, put a test
 around the inside each include file:
 
 foo.v (an include file):
-        \\=`ifdef _FOO_V        // include if not already included
-        \\=`else
+        \\=`ifndef _FOO_V        // include if not already included
         \\=`define _FOO_V
         ... contents of file
         \\=`endif // _FOO_V"
@@ -10066,7 +10673,7 @@ Results are cached if inside 
`verilog-preserve-dir-cache'."
 ;; (prin1 (verilog-dir-files ".")) nil)
 
 (defun verilog-dir-file-exists-p (filename)
-  "Return true if FILENAME exists.
+  "Return non-nil if FILENAME exists.
 Like `file-exists-p' but results are cached if inside
 `verilog-preserve-dir-cache'."
   (let* ((dirname (file-name-directory filename))
@@ -10105,7 +10712,7 @@ Allows version control to check out the file if need 
be."
             modi)))))
 
 (defun verilog-is-number (symbol)
-  "Return true if SYMBOL is number-like."
+  "Return non-nil if SYMBOL is number-like."
   (or (string-match "^[0-9 \t:]+$" symbol)
       (string-match "^[---]*[0-9]+$" symbol)
       (string-match "^[0-9 \t]+'s?[hdxbo][0-9a-fA-F_xz? \t]*$" symbol)))
@@ -10177,7 +10784,7 @@ Or, just the existing dirnames themselves if there are 
no wildcards."
   (unless dirnames
     (error "`verilog-library-directories' should include at least `.'"))
   (save-match-data
-    (setq dirnames (reverse dirnames)) ; not nreverse
+    (setq dirnames (reverse dirnames))  ; not nreverse
     (let ((dirlist nil)
           pattern dirfile dirfiles dirname root filename rest basefile)
       (setq dirnames (mapcar #'substitute-in-file-name dirnames))
@@ -10885,12 +11492,12 @@ This repairs those mis-inserted by an AUTOARG."
                                (if (equal (match-string 3 out) ">>")
                                    (int-to-string (ash (string-to-number 
(match-string 2 out))
                                                        (* -1 (string-to-number 
(match-string 4 out))))))
-                               (if (equal (match-string 3 out) "<<")
-                                   (int-to-string (ash (string-to-number 
(match-string 2 out))
-                                                       (string-to-number 
(match-string 4 out)))))
                                (if (equal (match-string 3 out) ">>>")
                                    (int-to-string (ash (string-to-number 
(match-string 2 out))
                                                        (* -1 (string-to-number 
(match-string 4 out))))))
+                               (if (equal (match-string 3 out) "<<")
+                                   (int-to-string (ash (string-to-number 
(match-string 2 out))
+                                                       (string-to-number 
(match-string 4 out)))))
                                (if (equal (match-string 3 out) "<<<")
                                    (int-to-string (ash (string-to-number 
(match-string 2 out))
                                                        (string-to-number 
(match-string 4 out)))))
@@ -10920,7 +11527,7 @@ This repairs those mis-inserted by an AUTOARG."
     (ceiling (/ (log value) (log 2)))))
 
 (defun verilog-typedef-name-p (variable-name)
-  "Return true if the VARIABLE-NAME is a type definition."
+  "Return non-nil if the VARIABLE-NAME is a type definition."
   (when verilog-typedef-regexp
     (verilog-string-match-fold verilog-typedef-regexp variable-name)))
 
@@ -11678,7 +12285,7 @@ If PAR-VALUES replace final strings with these 
parameter values."
                              (concat "." vl-modport) "")
                          dflt-bits))
     ;; Find template
-    (cond (tpl-ass         ; Template of exact port name
+    (cond (tpl-ass  ; Template of exact port name
           (setq tpl-net (nth 1 tpl-ass)))
          ((nth 1 tpl-list) ; Wildcards in template, search them
           (let ((wildcards (nth 1 tpl-list)))
@@ -12240,7 +12847,9 @@ For more information see the \\[verilog-faq] and forums 
at URL
           (cond ((not verilog-auto-inst-first-any)
                 (re-search-backward "," pt t)
                 (delete-char 1)
-                (insert ");")
+                 (when (looking-at "  ")
+                   (delete-char 1))  ; so we can align // Templated comments
+                 (insert ");")
                  (search-forward "\n")  ; Added by inst-port
                 (delete-char -1)
                  (if (search-forward ")" nil t)  ; From user, moved up a line
@@ -14645,7 +15254,7 @@ and the case items."
     (if (not (member v1 verilog-keywords))
        (save-excursion
          (setq verilog-sk-signal v1)
-         (verilog-beg-of-defun)
+         (verilog-re-search-backward verilog-defun-re nil 'move)
          (verilog-end-of-statement)
          (verilog-forward-syntactic-ws)
          (verilog-sk-def-reg)
@@ -14897,7 +15506,12 @@ Files are checked based on `verilog-library-flags'."
      '(
        verilog-active-low-regexp
        verilog-after-save-font-hook
+       verilog-align-assign-expr
+       verilog-align-comment-distance
+       verilog-align-decl-expr-comments
        verilog-align-ifelse
+       verilog-align-typedef-regexp
+       verilog-align-typedef-words
        verilog-assignment-delay
        verilog-auto-arg-sort
        verilog-auto-declare-nettype
@@ -14942,13 +15556,17 @@ Files are checked based on `verilog-library-flags'."
        verilog-compiler
        verilog-coverage
        verilog-delete-auto-hook
+       verilog-fontify-variables
        verilog-getopt-flags-hook
        verilog-highlight-grouping-keywords
        verilog-highlight-includes
        verilog-highlight-modules
        verilog-highlight-translate-off
        verilog-indent-begin-after-if
+       verilog-indent-class-inside-pkg
        verilog-indent-declaration-macros
+       verilog-indent-ignore-multiline-defines
+       verilog-indent-ignore-regexp
        verilog-indent-level
        verilog-indent-level-behavioral
        verilog-indent-level-declaration
diff --git a/lisp/progmodes/which-func.el b/lisp/progmodes/which-func.el
index 14b749296c..8a90b6d26e 100644
--- a/lisp/progmodes/which-func.el
+++ b/lisp/progmodes/which-func.el
@@ -51,9 +51,6 @@
 
 ;;; Code:
 
-;; So that we can use the edebug spec in `lisp-current-defun-name'.
-(require 'edebug)
-
 ;; Variables for customization
 ;; ---------------------------
 ;;
@@ -81,12 +78,22 @@ then Which Function mode is enabled in any major mode that 
supports it."
 This means that Which Function mode won't really do anything
 until you use Imenu, in these modes.  Note that files
 larger than `which-func-maxout' behave in this way too;
-Which Function mode doesn't do anything until you use Imenu."
+Which Function mode doesn't do anything until you use Imenu.
+
+If Which Function delays the initial display of buffers too much,
+e.g., when it is used with Eglot, and the language server takes a
+long time to send the information, you can use this option to delay
+activation of Which Function until Imenu is used for the first time."
   :type '(repeat (symbol :tag "Major mode")))
 
 (defcustom which-func-maxout 500000
   "Don't automatically compute the Imenu menu if buffer is this big or bigger.
-Zero means compute the Imenu menu regardless of size."
+Zero means compute the Imenu menu regardless of size.
+
+If Which Function delays the initial display of buffers too much,
+e.g., when it is used with Eglot, and the language server takes a
+long time to send the information, you can use this option to delay
+activation of Which Function until Imenu is used for the first time."
   :type 'integer)
 
 (defvar which-func-keymap
diff --git a/lisp/progmodes/xref.el b/lisp/progmodes/xref.el
index 1e4aa4eba5..0790d3a565 100644
--- a/lisp/progmodes/xref.el
+++ b/lisp/progmodes/xref.el
@@ -994,7 +994,7 @@ point."
   (setq-local add-log-current-defun-function
              #'xref--add-log-current-defun)
   (setq-local outline-minor-mode-cycle t
-              outline-minor-mode-use-buttons t
+              outline-minor-mode-use-buttons 'insert
               outline-search-function
               (lambda (&optional bound move backward looking-at)
                 (outline-search-text-property
diff --git a/lisp/replace.el b/lisp/replace.el
index c7ae77d128..302cb65543 100644
--- a/lisp/replace.el
+++ b/lisp/replace.el
@@ -1039,7 +1039,10 @@ They are deleted _before_ looking for the next match.  
Hence, a match
 starting on the same line at which another match ended is ignored.
 
 Return the number of deleted matching lines.  When called interactively,
-also print the number."
+also print the number.
+
+If you want to not just delete the lines, but also add them to
+the kill ring, use the \\[kill-matching-lines] command instead."
   (interactive
    (progn
      (barf-if-buffer-read-only)
@@ -1101,7 +1104,10 @@ Hence, a match starting on the same line at which 
another match
 ended is ignored.
 
 Return the number of killed matching lines.  When called
-interactively, also print the number."
+interactively, also print the number.
+
+If you merely want to delete the lines, without adding them to
+the kill ring, the \\[delete-matching-lines] command is faster."
   (interactive
    (progn
      (barf-if-buffer-read-only)
diff --git a/lisp/server.el b/lisp/server.el
index 7e713eaecd..8f4ca4cbc6 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -273,6 +273,11 @@ If nil, no instructions are displayed."
   :version "28.1"
   :type 'boolean)
 
+(defvar server-stop-automatically)      ; Defined below to avoid recursive 
load.
+
+(defvar server-stop-automatically--timer nil
+  "The timer object for `server-stop-automatically--maybe-kill-emacs'.")
+
 ;; We do not use `temporary-file-directory' here, because emacsclient
 ;; does not read the init file.
 (defvar server-socket-dir
@@ -636,7 +641,8 @@ anyway."
       (setq stopped-p t
             server-process nil
             server-mode nil
-            global-minor-modes (delq 'server-mode global-minor-modes)))
+            global-minor-modes (delq 'server-mode global-minor-modes))
+      (server-apply-stop-automatically))
     (unwind-protect
         ;; Delete the socket files made by previous server
         ;; invocations.
@@ -757,6 +763,7 @@ the `server-process' variable."
                         (list :family 'local
                               :service server-file
                               :plist '(:authenticated t)))))
+          (server-apply-stop-automatically)
          (unless server-process (error "Could not start server process"))
           (server-log "Started server")
          (process-put server-process :server-file server-file)
@@ -1769,9 +1776,6 @@ be a cons cell (LINENUMBER . COLUMNNUMBER)."
     (when server-raise-frame
       (select-frame-set-input-focus (window-frame)))))
 
-(defvar server-stop-automatically nil
-  "Internal status variable for `server-stop-automatically'.")
-
 ;;;###autoload
 (defun server-save-buffers-kill-terminal (arg)
   ;; Called from save-buffers-kill-terminal in files.el.
@@ -1779,11 +1783,19 @@ be a cons cell (LINENUMBER . COLUMNNUMBER)."
 With ARG non-nil, silently save all file-visiting buffers, then kill.
 
 If emacsclient was started with a list of filenames to edit, then
-only these files will be asked to be saved."
-  (let ((proc (frame-parameter nil 'client)))
+only these files will be asked to be saved.
+
+When running Emacs as a daemon and with
+`server-stop-automatically' (which see) set to `kill-terminal' or
+`delete-frame', this function may call `save-buffers-kill-emacs'
+if there are no other active clients."
+  (let ((stop-automatically
+         (and (daemonp)
+              (memq server-stop-automatically '(kill-terminal delete-frame))))
+        (proc (frame-parameter nil 'client)))
     (cond ((eq proc 'nowait)
           ;; Nowait frames have no client buffer list.
-          (if (length> (frame-list) (if server-stop-automatically 2 1))
+          (if (length> (frame-list) (if stop-automatically 2 1))
                ;; If there are any other frames, only delete this one.
                ;; When `server-stop-automatically' is set, don't count
                ;; the daemon frame.
@@ -1792,7 +1804,7 @@ only these files will be asked to be saved."
             ;; If we're the last frame standing, kill Emacs.
             (save-buffers-kill-emacs arg)))
          ((processp proc)
-           (if (or (not server-stop-automatically)
+           (if (or (not stop-automatically)
                    (length> server-clients 1)
                    (seq-some
                     (lambda (frame)
@@ -1818,31 +1830,14 @@ only these files will be asked to be saved."
              (save-buffers-kill-emacs arg)))
          (t (error "Invalid client frame")))))
 
-(defun server-stop-automatically--handle-delete-frame (frame)
-  "Handle deletion of FRAME when `server-stop-automatically' is used."
-  (when server-stop-automatically
-    (if (if (and (processp (frame-parameter frame 'client))
-                (eq this-command 'save-buffers-kill-terminal))
-           (progn
-             (dolist (f (frame-list))
-               (when (and (eq (frame-parameter frame 'client)
-                              (frame-parameter f 'client))
-                          (not (eq frame f)))
-                 (set-frame-parameter f 'client nil)
-                 (let ((server-stop-automatically nil))
-                   (delete-frame f))))
-             (if (cddr (frame-list))
-                 (let ((server-stop-automatically nil))
-                   (delete-frame frame)
-                   nil)
-               t))
-         (null (cddr (frame-list))))
-       (let ((server-stop-automatically nil))
-         (save-buffers-kill-emacs)
-         (delete-frame frame)))))
+(defun server-stop-automatically--handle-delete-frame (_frame)
+  "Handle deletion of FRAME when `server-stop-automatically' is 
`delete-frame'."
+  (when (null (cddr (frame-list)))
+    (let ((server-stop-automatically nil))
+      (save-buffers-kill-emacs))))
 
 (defun server-stop-automatically--maybe-kill-emacs ()
-  "Handle closing of Emacs daemon when `server-stop-automatically' is used."
+  "Handle closing of Emacs daemon when `server-stop-automatically' is `empty'."
   (unless (cdr (frame-list))
     (when (and
           (not (memq t (mapcar (lambda (b)
@@ -1856,41 +1851,70 @@ only these files will be asked to be saved."
                                (process-list)))))
       (kill-emacs))))
 
-;;;###autoload
-(defun server-stop-automatically (arg)
-  "Automatically stop server as specified by ARG.
-
-If ARG is the symbol `empty', stop the server when it has no
+(defun server-apply-stop-automatically ()
+  "Apply the current value of `server-stop-automatically'.
+This function adds or removes the necessary helpers to manage
+stopping the Emacs server automatically, depending on the whether
+the server is running or not.  This function only applies when
+running Emacs as a daemon."
+  (when (daemonp)
+    (let (empty-timer-p delete-frame-p)
+      (when server-process
+        (pcase server-stop-automatically
+          ('empty        (setq empty-timer-p t))
+          ('delete-frame (setq delete-frame-p t))))
+      ;; Start or stop the timer.
+      (if empty-timer-p
+          (unless server-stop-automatically--timer
+            (setq server-stop-automatically--timer
+                  (run-with-timer
+                   10 2
+                  #'server-stop-automatically--maybe-kill-emacs)))
+        (when server-stop-automatically--timer
+          (cancel-timer server-stop-automatically--timer)
+          (setq server-stop-automatically--timer nil)))
+      ;; Add or remove the delete-frame hook.
+      (if delete-frame-p
+          (add-hook 'delete-frame-functions
+                   #'server-stop-automatically--handle-delete-frame)
+        (remove-hook 'delete-frame-functions
+                     #'server-stop-automatically--handle-delete-frame))))
+  ;; Return the current value of `server-stop-automatically'.
+  server-stop-automatically)
+
+(defcustom server-stop-automatically nil
+  "If non-nil, stop the server under the requested conditions.
+
+If this is the symbol `empty', stop the server when it has no
 remaining clients, no remaining unsaved file-visiting buffers,
 and no running processes with a `query-on-exit' flag.
 
-If ARG is the symbol `delete-frame', ask the user when the last
+If this is the symbol `delete-frame', ask the user when the last
 frame is deleted whether each unsaved file-visiting buffer must
 be saved and each running process with a `query-on-exit' flag
 can be stopped, and if so, stop the server itself.
 
-If ARG is the symbol `kill-terminal', ask the user when the
+If this is the symbol `kill-terminal', ask the user when the
 terminal is killed with \\[save-buffers-kill-terminal] \
 whether each unsaved file-visiting
 buffer must be saved and each running process with a `query-on-exit'
-flag can be stopped, and if so, stop the server itself.
-
-Any other value of ARG will cause this function to signal an error.
+flag can be stopped, and if so, stop the server itself."
+  :type '(choice
+          (const :tag "Never" nil)
+          (const :tag "When no clients, unsaved files, or processes"
+                 empty)
+          (const :tag "When killing last terminal" kill-terminal)
+          (const :tag "When killing last terminal or frame" delete-frame))
+  :set (lambda (symbol value)
+         (set-default symbol value)
+         (server-apply-stop-automatically))
+  :version "29.1")
 
-This function is meant to be called from the user init file."
-  (when (daemonp)
-    (setq server-stop-automatically arg)
-    (cond
-     ((eq arg 'empty)
-      (setq server-stop-automatically nil)
-      (run-with-timer 10 2
-                     #'server-stop-automatically--maybe-kill-emacs))
-     ((eq arg 'delete-frame)
-      (add-hook 'delete-frame-functions
-               #'server-stop-automatically--handle-delete-frame))
-     ((eq arg 'kill-terminal))
-     (t
-      (error "Unexpected argument")))))
+;;;###autoload
+(defun server-stop-automatically (value)
+  "Automatically stop the Emacs server as specified by VALUE.
+This sets the variable `server-stop-automatically' (which see)."
+  (setopt server-stop-automatically value))
 
 (define-key ctl-x-map "#" 'server-edit)
 
@@ -1911,10 +1935,11 @@ Returns the result of the evaluation, or signals an 
error if it
 cannot contact the specified server.  For example:
   (server-eval-at \"server\" \\='(emacs-pid))
 returns the process ID of the Emacs instance running \"server\"."
-  (let ((server-file (server--file-name))
-        (coding-system-for-read 'binary)
-        (coding-system-for-write 'binary)
-        address port secret process)
+  (let* ((server-dir (if server-use-tcp server-auth-dir server-socket-dir))
+         (server-file (expand-file-name server server-dir))
+         (coding-system-for-read 'binary)
+         (coding-system-for-write 'binary)
+         address port secret process)
     (unless (file-exists-p server-file)
       (error "No such server: %s" server))
     (with-temp-buffer
diff --git a/lisp/shell.el b/lisp/shell.el
index b396bc2b18..dadbdcbc03 100644
--- a/lisp/shell.el
+++ b/lisp/shell.el
@@ -1162,6 +1162,7 @@ line output and parses it to form the new directory 
stack."
          (dlsl nil)
          (pos 0)
          (ds nil))
+    (setq dls (string-trim-right dls "[ ]+"))
     ;; Split the dirlist into whitespace and non-whitespace chunks.
     ;; dlsl will be a reversed list of tokens.
     (while (string-match "\\(\\S-+\\|\\s-+\\)" dls pos)
diff --git a/lisp/simple.el b/lisp/simple.el
index 893a43b03f..f85428ca74 100644
--- a/lisp/simple.el
+++ b/lisp/simple.el
@@ -2929,11 +2929,12 @@ that was current when the minibuffer was activated."
                       (window-buffer (minibuffer-selected-window))))
 
 (defun goto-history-element (nabs)
-  "Puts element of the minibuffer history in the minibuffer.
-The argument NABS specifies the absolute history position in
-descending order, where 0 means the current element and a
-positive number N means the Nth previous element.  NABS being a
-negative number -N means the Nth entry of \"future history.\""
+  "Insert into the minibuffer the element of minibuffer history specified by 
NABS.
+Interactively, NABS is the prefix numeric argument, and defaults to 1.
+It specifies the absolute history position in descending order,
+where 0 means the current element and a positive number N means
+the Nth previous element.  NABS that is a negative number -N means
+the Nth entry of \"future history.\""
   (interactive "p")
   (when (and (not minibuffer-default-add-done)
             (functionp minibuffer-default-add-function)
@@ -2989,17 +2990,17 @@ negative number -N means the Nth entry of \"future 
history.\""
     (goto-char (or minibuffer-temporary-goal-position (point-max)))))
 
 (defun next-history-element (n)
-  "Puts next element of the minibuffer history in the minibuffer.
-With argument N, it uses the Nth following element.  The position
-in the history can go beyond the current position and invoke \"future
-history.\""
+  "Insert into the minibuffer the Nth next element of minibuffer history.
+Interactively, N is the prefix numeric argument and defaults to 1.
+The value N can go beyond the current position in the minibuffer
+history,  and invoke \"future history.\""
   (interactive "p")
   (or (zerop n)
       (goto-history-element (- minibuffer-history-position n))))
 
 (defun previous-history-element (n)
-  "Puts previous element of the minibuffer history in the minibuffer.
-With argument N, it uses the Nth previous element."
+  "Insert into the minibuffer the Nth previous element of minibuffer history.
+Interactively, N is the prefix numeric argument and defaults to 1."
   (interactive "p")
   (or (zerop n)
       (goto-history-element (+ minibuffer-history-position n))))
@@ -9578,8 +9579,6 @@ makes it easier to edit it."
     (define-key map "\C-m" 'choose-completion)
     (define-key map "\e\e\e" 'delete-completion-window)
     (define-key map [remap keyboard-quit] #'delete-completion-window)
-    (define-key map [up] 'previous-line-completion)
-    (define-key map [down] 'next-line-completion)
     (define-key map [left] 'previous-completion)
     (define-key map [right] 'next-completion)
     (define-key map [?\t] 'next-completion)
@@ -9639,8 +9638,7 @@ Go to the window from which completion was requested."
 
 (defcustom completion-auto-wrap t
   "Non-nil means to wrap around when selecting completion options.
-This affects the commands `next-completion', `previous-completion',
-`next-line-completion' and `previous-line-completion'.
+This affects the commands `next-completion' and `previous-completion'.
 When `completion-auto-select' is t, it wraps through the minibuffer
 for the commands bound to the TAB key."
   :type 'boolean
@@ -9746,73 +9744,6 @@ Also see the `completion-auto-wrap' variable."
     (when (/= 0 n)
       (switch-to-minibuffer))))
 
-(defun previous-line-completion (&optional n)
-  "Move to the item on the previous line in the completion list.
-With prefix argument N, move back N items line-wise (negative N
-means move forward).
-
-Also see the `completion-auto-wrap' variable."
-  (interactive "p")
-  (next-line-completion (- n)))
-
-(defun next-line-completion (&optional n)
-  "Move to the item on the next line in the completion list.
-With prefix argument N, move N items line-wise (negative N
-means move backward).
-
-Also see the `completion-auto-wrap' variable."
-  (interactive "p")
-  (let ((column (current-column))
-        pos)
-    (catch 'bound
-      (while (> n 0)
-        (setq pos nil)
-        (save-excursion
-          (while (and (not pos) (not (eobp)))
-            (forward-line 1)
-            (when (and (not (eobp))
-                       (eq (move-to-column column) column)
-                       (get-text-property (point) 'mouse-face))
-              (setq pos (point)))))
-        (if pos (goto-char pos)
-          (when completion-auto-wrap
-            (save-excursion
-              (goto-char (point-min))
-              (when (and (eq (move-to-column column) column)
-                         (get-text-property (point) 'mouse-face))
-                (setq pos (point)))
-              (while (and (not pos) (not (eobp)))
-                (forward-line 1)
-                (when (and (eq (move-to-column column) column)
-                           (get-text-property (point) 'mouse-face))
-                  (setq pos (point)))))
-            (if pos (goto-char pos))))
-        (setq n (1- n)))
-
-      (while (< n 0)
-        (setq pos nil)
-        (save-excursion
-          (while (and (not pos) (not (bobp)))
-            (forward-line -1)
-            (when (and (not (bobp))
-                       (eq (move-to-column column) column)
-                       (get-text-property (point) 'mouse-face))
-              (setq pos (point)))))
-        (if pos (goto-char pos)
-          (when completion-auto-wrap
-            (save-excursion
-              (goto-char (point-max))
-              (when (and (eq (move-to-column column) column)
-                         (get-text-property (point) 'mouse-face))
-                (setq pos (point)))
-              (while (and (not pos) (not (bobp)))
-                (forward-line -1)
-                (when (and (eq (move-to-column column) column)
-                           (get-text-property (point) 'mouse-face))
-                  (setq pos (point)))))
-            (if pos (goto-char pos))))
-        (setq n (1+ n))))))
-
 (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.
diff --git a/lisp/so-long.el b/lisp/so-long.el
index 661f5ee57a..fc99162325 100644
--- a/lisp/so-long.el
+++ b/lisp/so-long.el
@@ -986,7 +986,7 @@ See also `so-long-mode-line-info'."
 ;; Modes that go slowly and line lengths excessive
 ;; Font-lock performance becoming oppressive
 ;; All of my CPU tied up with strings
-;; These are a few of my least-favourite things
+;; These are a few of my least-favorite things
 
 (defvar-local so-long-original-values nil
   "Alist holding the buffer's original `major-mode' value, and other data.
diff --git a/lisp/subr.el b/lisp/subr.el
index 21f43092d4..e142eaa810 100644
--- a/lisp/subr.el
+++ b/lisp/subr.el
@@ -3855,7 +3855,7 @@ If MESSAGE is nil, instructions to type EXIT-CHAR are 
displayed there."
   (let ((o1 (if (overlay-buffer o)
                 (make-overlay (overlay-start o) (overlay-end o)
                               ;; FIXME: there's no easy way to find the
-                              ;; insertion-type of the two markers.
+                              ;; insertion-type of overlay's start and end.
                               (overlay-buffer o))
               (let ((o1 (make-overlay (point-min) (point-min))))
                 (delete-overlay o1)
diff --git a/lisp/tab-bar.el b/lisp/tab-bar.el
index 162e63fe23..065116d512 100644
--- a/lisp/tab-bar.el
+++ b/lisp/tab-bar.el
@@ -105,7 +105,7 @@ For easier selection of tabs by their numbers, consider 
customizing
               (const hyper)
               (const super)
               (const alt))
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          ;; Reenable the tab-bar with new keybindings
@@ -116,23 +116,23 @@ For easier selection of tabs by their numbers, consider 
customizing
   :version "27.1")
 
 (defun tab-bar--define-keys ()
-  "Install key bindings for switching between tabs if the user has configured 
them."
+  "Install key bindings to switch between tabs if so configured."
   (when tab-bar-select-tab-modifiers
     (global-set-key (vector (append tab-bar-select-tab-modifiers (list ?0)))
-                    'tab-recent)
+                    #'tab-recent)
     (dotimes (i 8)
       (global-set-key (vector (append tab-bar-select-tab-modifiers
                                       (list (+ i 1 ?0))))
-                      'tab-bar-select-tab))
+                      #'tab-bar-select-tab))
     (global-set-key (vector (append tab-bar-select-tab-modifiers (list ?9)))
-                    'tab-last))
+                    #'tab-last))
   ;; Don't override user customized key bindings
   (unless (global-key-binding [(control tab)])
-    (global-set-key [(control tab)] 'tab-next))
+    (global-set-key [(control tab)] #'tab-next))
   (unless (global-key-binding [(control shift tab)])
-    (global-set-key [(control shift tab)] 'tab-previous))
+    (global-set-key [(control shift tab)] #'tab-previous))
   (unless (global-key-binding [(control shift iso-lefttab)])
-    (global-set-key [(control shift iso-lefttab)] 'tab-previous))
+    (global-set-key [(control shift iso-lefttab)] #'tab-previous))
 
   ;; Replace default value with a condition that supports displaying
   ;; global-mode-string in the tab bar instead of the mode line.
@@ -157,6 +157,9 @@ For easier selection of tabs by their numbers, consider 
customizing
 (defun tab-bar--load-buttons ()
   "Load the icons for the tab buttons."
   (require 'icons)
+  (declare-function icon-string "icons" (name))
+  (declare-function iconp "icons" (object))
+  (declare-function icons--register "icons")
   (unless (iconp 'tab-bar-new)
     (define-icon tab-bar-new nil
       `((image "tabs/new.xpm"
@@ -227,7 +230,8 @@ a list of frames to update."
   ;; Update `default-frame-alist'
   (when (eq frames t)
     (setq default-frame-alist
-          (cons (cons 'tab-bar-lines (if (and tab-bar-mode (eq tab-bar-show 
t)) 1 0))
+          (cons (cons 'tab-bar-lines
+                      (if (and tab-bar-mode (eq tab-bar-show t)) 1 0))
                 (assq-delete-all 'tab-bar-lines default-frame-alist)))))
 
 (define-minor-mode tab-bar-mode
@@ -279,7 +283,8 @@ It returns a list of the form (KEY KEY-BINDING CLOSE-P), 
where:
     ;; This code is used when you click the mouse in the tab bar
     ;; on a console which has no window system but does have a mouse.
     (let* ((x-position (car (posn-x-y posn)))
-           (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps))) 
[tab-bar]))
+           (keymap (lookup-key (cons 'keymap (nreverse (current-active-maps)))
+                               [tab-bar]))
            (column 0))
       (when x-position
         (catch 'done
@@ -416,7 +421,7 @@ at the mouse-down event to the position at mouse-up event."
   "S-<wheel-right>" #'tab-bar-move-tab)
 
 (global-set-key [tab-bar]
-                `(menu-item ,(purecopy "tab bar") ignore
+                `(menu-item ,(purecopy "tab bar") ,(make-sparse-keymap)
                             :filter tab-bar-make-keymap))
 
 (defun tab-bar-make-keymap (&optional _ignore)
@@ -478,7 +483,7 @@ you can use the command `toggle-frame-tab-bar'."
   :type '(choice (const :tag "Always" t)
                  (const :tag "When more than one tab" 1)
                  (const :tag "Never" nil))
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (if val
@@ -529,7 +534,7 @@ to get the group name."
   "If non-nil, show the \"New tab\" button in the tab bar.
 When this is nil, you can create new tabs with \\[tab-new]."
   :type 'boolean
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -550,7 +555,7 @@ If nil, don't show it at all."
                  (const :tag "On selected tab" selected)
                  (const :tag "On non-selected tabs" non-selected)
                  (const :tag "None" nil))
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -574,7 +579,7 @@ If nil, don't show it at all."
 This helps to select the tab by its number using `tab-bar-select-tab'
 and `tab-bar-select-tab-modifiers'."
   :type 'boolean
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -604,7 +609,7 @@ from all windows in the window configuration."
                  (const :tag "All window buffers"
                         tab-bar-tab-name-all)
                  (function  :tag "Function"))
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -704,7 +709,7 @@ Function gets one argument: a tab."
 Function gets two arguments, the tab and its number, and should return
 the formatted tab name to display in the tab bar."
   :type 'function
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -753,7 +758,7 @@ of the mode line.  Replacing `tab-bar-format-tabs' with
              tab-bar-format-add-tab
              tab-bar-format-align-right
              tab-bar-format-global)
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -815,7 +820,8 @@ You can hide these buttons by customizing `tab-bar-format' 
and removing
         ,(alist-get 'binding tab)
         :help "Click to visit tab"))))
    (when (alist-get 'close-binding tab)
-     `((,(if (eq (car tab) 'current-tab) 'C-current-tab (intern (format 
"C-tab-%i" i)))
+     `((,(if (eq (car tab) 'current-tab) 'C-current-tab
+           (intern (format "C-tab-%i" i)))
         menu-item ""
         ,(alist-get 'close-binding tab))))))
 
@@ -832,7 +838,7 @@ You can hide these buttons by customizing `tab-bar-format' 
and removing
   "Function to get a tab group name.
 Function gets one argument: a tab."
   :type 'function
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
@@ -844,21 +850,22 @@ Function gets one argument: a tab."
 
 (defcustom tab-bar-tab-group-format-function #'tab-bar-tab-group-format-default
   "Function to format a tab group name.
-Function gets two arguments, a tab with a group name and its number,
-and should return the formatted tab group name to display in the tab bar."
+Function gets three arguments, a tab with a group name, its number, and
+an optional value that is non-nil when the tab is from the current group.
+It should return the formatted tab group name to display in the tab bar."
   :type 'function
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (force-mode-line-update))
   :group 'tab-bar
   :version "28.1")
 
-(defun tab-bar-tab-group-format-default (tab i)
+(defun tab-bar-tab-group-format-default (tab i &optional current-p)
   (propertize
-   (concat (if tab-bar-tab-hints (format "%d " i) "")
+   (concat (if (and tab-bar-tab-hints (not current-p)) (format "%d " i) "")
            (funcall tab-bar-tab-group-function tab))
-   'face 'tab-bar-tab-group-inactive))
+   'face (if current-p 'tab-bar-tab-group-current 
'tab-bar-tab-group-inactive)))
 
 (defcustom tab-bar-tab-group-face-function #'tab-bar-tab-group-face-default
   "Function to define a tab group face.
@@ -882,8 +889,14 @@ when the tab is current.  Return the result as a keymap."
    `((,(intern (format "group-%i" i))
       menu-item
       ,(if current-p
-           (propertize (funcall tab-bar-tab-group-function tab)
-                       'face 'tab-bar-tab-group-current)
+           (condition-case nil
+               (funcall tab-bar-tab-group-format-function tab i current-p)
+             ;; We used to define tab-bar-tab-group-format-function as
+             ;; taking two arguments but after adding the third argument
+             ;; we need to provide backwards-compatibility.
+             (wrong-number-of-arguments
+              (propertize (funcall tab-bar-tab-group-function tab)
+                          'face 'tab-bar-tab-group-current)))
          (funcall tab-bar-tab-group-format-function tab i))
       ,(if current-p 'ignore
          (or
@@ -912,7 +925,8 @@ when the tab is current.  Return the result as a keymap."
                    (when (and (not (equal previous-group tab-group)) tab-group)
                      (tab-bar--format-tab-group tab i t))
                    ;; Override default tab faces to use group faces
-                   (let ((tab-bar-tab-face-function 
tab-bar-tab-group-face-function))
+                   (let ((tab-bar-tab-face-function
+                          tab-bar-tab-group-face-function))
                      (tab-bar--format-tab tab i))))
                  ;; Show first tab of other groups with a group name
                  ((not (equal previous-group tab-group))
@@ -941,7 +955,8 @@ when the tab is current.  Return the result as a keymap."
                           ;; when windows are split horizontally (bug#59620)
                           (if (window-system)
                               `(space :align-to (- right (,hpos)))
-                            `(space :align-to (,(- (frame-inner-width) 
hpos)))))))
+                            `(space :align-to (,(- (frame-inner-width)
+                                                   hpos)))))))
     `((align-right menu-item ,str ignore))))
 
 (defun tab-bar-format-global ()
@@ -1011,7 +1026,7 @@ This variable has effect only when `tab-bar-auto-width' 
is non-nil."
           (const :tag "No limit" nil)
           (list (integer :tag "Max width (pixels)" :value 220)
                 (integer :tag "Max width (chars)" :value 20)))
-  :initialize 'custom-initialize-default
+  :initialize #'custom-initialize-default
   :set (lambda (sym val)
          (set-default sym val)
          (setq tab-bar--fixed-width-hash nil))
@@ -1080,12 +1095,14 @@ tab bar might wrap to the second line when it 
shouldn't.")
                        curr-width)
                   (cond
                    ((< prev-width width)
-                    (let* ((space (apply 'propertize " "
+                    (let* ((space (apply #'propertize " "
                                          (text-properties-at 0 name)))
                            (ins-pos (- len (if close-p 1 0)))
                            (prev-name name))
                       (while continue
-                        (setf (substring name ins-pos ins-pos) space)
+                        (setq name (concat (substring name 0 ins-pos)
+                                           space
+                                           (substring name ins-pos)))
                         (setq curr-width (string-pixel-width name))
                         (if (and (< curr-width width)
                                  (> curr-width prev-width))
@@ -1098,7 +1115,8 @@ tab bar might wrap to the second line when it shouldn't.")
                     (let ((del-pos1 (if close-p -2 -1))
                           (del-pos2 (if close-p -1 nil)))
                       (while continue
-                        (setf (substring name del-pos1 del-pos2) "")
+                        (setq name (concat (substring name 0 del-pos1)
+                                           (substring name del-pos2)))
                         (setq curr-width (string-pixel-width name))
                         (if (and (> curr-width width)
                                  (< curr-width prev-width))
@@ -1302,11 +1320,13 @@ Negative TAB-NUMBER counts tabs from the end of the tab 
bar."
 
             (when tab-bar-history-mode
               (puthash (selected-frame)
-                       (and (window-configuration-p (alist-get 'wc (car 
wc-history-back)))
+                       (and (window-configuration-p
+                             (alist-get 'wc (car wc-history-back)))
                             wc-history-back)
                        tab-bar-history-back)
               (puthash (selected-frame)
-                       (and (window-configuration-p (alist-get 'wc (car 
wc-history-forward)))
+                       (and (window-configuration-p
+                             (alist-get 'wc (car wc-history-forward)))
                             wc-history-forward)
                        tab-bar-history-forward))))
 
@@ -1332,7 +1352,8 @@ Negative TAB-NUMBER counts tabs from the end of the tab 
bar."
 
         (when from-index
           (setf (nth from-index tabs) from-tab))
-        (setf (nth to-index tabs) (tab-bar--current-tab-make (nth to-index 
tabs)))
+        (setf (nth to-index tabs)
+              (tab-bar--current-tab-make (nth to-index tabs)))
 
         (unless tab-bar-mode
           (message "Selected tab '%s'" (alist-get 'name to-tab))))
@@ -1399,7 +1420,7 @@ and rename it to NAME."
       (tab-bar-new-tab)
       (tab-bar-rename-tab name))))
 
-(defalias 'tab-bar-select-tab-by-name 'tab-bar-switch-to-tab)
+(defalias 'tab-bar-select-tab-by-name #'tab-bar-switch-to-tab)
 
 
 (defun tab-bar-move-tab-to (to-number &optional from-number)
@@ -1414,7 +1435,8 @@ where argument addressing is relative."
          (from-number (or from-number (1+ (tab-bar--current-tab-index tabs))))
          (from-tab (nth (1- from-number) tabs))
          (to-number (if to-number (prefix-numeric-value to-number) 1))
-         (to-number (if (< to-number 0) (+ (length tabs) (1+ to-number)) 
to-number))
+         (to-number (if (< to-number 0) (+ (length tabs) (1+ to-number))
+                      to-number))
          (to-index (max 0 (min (1- to-number) (1- (length tabs))))))
     (setq tabs (delq from-tab tabs))
     (cl-pushnew from-tab (nthcdr to-index tabs))
@@ -1440,7 +1462,8 @@ Like `tab-bar-move-tab', but moves in the opposite 
direction."
   (interactive "p")
   (tab-bar-move-tab (- (or arg 1))))
 
-(defun tab-bar-move-tab-to-frame (arg &optional from-frame from-number 
to-frame to-number)
+(defun tab-bar-move-tab-to-frame (arg &optional from-frame from-number
+                                      to-frame to-number)
   "Move tab from FROM-NUMBER position to new position at TO-NUMBER.
 FROM-NUMBER defaults to the current tab number.
 FROM-NUMBER and TO-NUMBER count from 1.
@@ -1456,7 +1479,8 @@ to which to move the tab; ARG defaults to 1."
       (setq to-frame (next-frame to-frame))))
   (unless (eq from-frame to-frame)
     (let* ((from-tabs (funcall tab-bar-tabs-function from-frame))
-           (from-number (or from-number (1+ (tab-bar--current-tab-index 
from-tabs))))
+           (from-number (or from-number
+                            (1+ (tab-bar--current-tab-index from-tabs))))
            (from-tab (nth (1- from-number) from-tabs))
            (to-tabs (funcall tab-bar-tabs-function to-frame))
            (to-index (max 0 (min (1- (or to-number 1)) (1- (length 
to-tabs))))))
@@ -1478,7 +1502,8 @@ to which to move the tab; ARG defaults to 1."
 FROM-NUMBER defaults to the current tab (which happens interactively)."
   (interactive (list (1+ (tab-bar--current-tab-index))))
   (let* ((tabs (funcall tab-bar-tabs-function))
-         (tab-index (1- (or from-number (1+ (tab-bar--current-tab-index 
tabs)))))
+         (tab-index (1- (or from-number
+                            (1+ (tab-bar--current-tab-index tabs)))))
          (tab-name (alist-get 'name (nth tab-index tabs)))
          ;; On some window managers, `make-frame' selects the new frame,
          ;; so previously selected frame is saved to `from-frame'.
@@ -1741,7 +1766,8 @@ for the last tab on a frame is determined by
           ;; Select another tab before deleting the current tab
           (let ((to-index (or (if to-number (1- to-number))
                               (pcase tab-bar-close-tab-select
-                                ('left (1- (if (< current-index 1) 2 
current-index)))
+                                ('left (1- (if (< current-index 1) 2
+                                             current-index)))
                                 ('right (if (> (length tabs) (1+ 
current-index))
                                             (1+ current-index)
                                           (1- current-index)))
@@ -1766,7 +1792,8 @@ for the last tab on a frame is determined by
 
         (force-mode-line-update)
         (unless tab-bar-mode
-          (message "Deleted tab and switched to %s" 
tab-bar-close-tab-select))))))
+          (message "Deleted tab and switched to %s"
+                   tab-bar-close-tab-select))))))
 
 (defun tab-bar-close-tab-by-name (name)
   "Close the tab given its NAME.
@@ -1857,7 +1884,8 @@ If NAME is the empty string, then use the automatic name
 function `tab-bar-tab-name-function'."
   (interactive
    (let* ((tabs (funcall tab-bar-tabs-function))
-          (tab-number (or current-prefix-arg (1+ (tab-bar--current-tab-index 
tabs))))
+          (tab-number (or current-prefix-arg
+                          (1+ (tab-bar--current-tab-index tabs))))
           (tab-name (alist-get 'name (nth (1- tab-number) tabs))))
      (list (read-from-minibuffer
             "New name for tab (leave blank for automatic naming): "
@@ -2122,10 +2150,10 @@ and can restore them."
             :version "29.1"))
         (setq tab-bar-forward-button (icon-string 'tab-bar-forward))
 
-        (add-hook 'pre-command-hook 'tab-bar--history-pre-change)
-        (add-hook 'window-configuration-change-hook 'tab-bar--history-change))
-    (remove-hook 'pre-command-hook 'tab-bar--history-pre-change)
-    (remove-hook 'window-configuration-change-hook 'tab-bar--history-change)))
+        (add-hook 'pre-command-hook #'tab-bar--history-pre-change)
+        (add-hook 'window-configuration-change-hook #'tab-bar--history-change))
+    (remove-hook 'pre-command-hook #'tab-bar--history-pre-change)
+    (remove-hook 'window-configuration-change-hook #'tab-bar--history-change)))
 
 
 ;;; Non-graphical access to frame-local tabs (named window configurations)
@@ -2165,8 +2193,9 @@ For more information, see the function `tab-switcher'."
          (tabs (sort tabs (lambda (a b) (< (alist-get 'time b)
                                            (alist-get 'time a))))))
     (with-current-buffer (get-buffer-create
-                          (format " *Tabs*<%s>" (or (frame-parameter nil 
'window-id)
-                                                    (frame-parameter nil 
'name))))
+                          (format " *Tabs*<%s>"
+                                  (or (frame-parameter nil 'window-id)
+                                      (frame-parameter nil 'name))))
       (setq buffer-read-only nil)
       (erase-buffer)
       (tab-switcher-mode)
@@ -2181,7 +2210,8 @@ For more information, see the function `tab-switcher'."
                          (propertize
                           (alist-get 'name tab)
                           'mouse-face 'highlight
-                          'help-echo "mouse-2: select this window 
configuration"))
+                          'help-echo
+                          "mouse-2: select this window configuration"))
                  'tab tab)))
       (goto-char (point-min))
       (goto-char (or (next-single-property-change (point) 'tab) (point-min)))
@@ -2257,8 +2287,8 @@ Interactively, ARG is the prefix numeric argument and 
defaults to 1."
   (move-to-column tab-switcher-column))
 
 (defun tab-switcher-unmark (&optional backup)
-  "Cancel requested operations on window configuration on this line and move 
down.
-With prefix arg, move up instead."
+  "Cancel operations on window configuration on this line and move down.
+With prefix arg BACKUP, move up instead."
   (interactive "P")
   (beginning-of-line)
   (move-to-column tab-switcher-column)
@@ -2269,7 +2299,7 @@ With prefix arg, move up instead."
   (move-to-column tab-switcher-column))
 
 (defun tab-switcher-backup-unmark ()
-  "Move up one line and cancel requested operations on window configuration 
there."
+  "Move up one line and cancel operations on window configuration there."
   (interactive)
   (forward-line -1)
   (tab-switcher-unmark)
@@ -2277,9 +2307,10 @@ With prefix arg, move up instead."
   (move-to-column tab-switcher-column))
 
 (defun tab-switcher-delete (&optional arg)
-  "Mark window configuration on this line to be deleted by 
\\<tab-switcher-mode-map>\\[tab-switcher-execute] command.
+  "Mark window configuration on this line to be deleted.
 Prefix arg says how many window configurations to delete.
-Negative arg means delete backwards."
+Negative arg means delete backwards.
+The deletion will be done by the 
\\<tab-switcher-mode-map>\\[tab-switcher-execute] command."
   (interactive "p")
   (let ((buffer-read-only nil))
     (if (or (null arg) (= arg 0))
@@ -2297,8 +2328,9 @@ Negative arg means delete backwards."
     (move-to-column tab-switcher-column)))
 
 (defun tab-switcher-delete-backwards (&optional arg)
-  "Mark window configuration on this line to be deleted by 
\\<tab-switcher-mode-map>\\[tab-switcher-execute] command.
-Then move up one line.  Prefix arg means move that many lines."
+  "Mark window configuration on this line to be deleted.
+Then move up one line.  Prefix arg means move that many lines.
+The deletion will be done by the 
\\<tab-switcher-mode-map>\\[tab-switcher-execute] command."
   (interactive "p")
   (tab-switcher-delete (- (or arg 1))))
 
@@ -2311,7 +2343,9 @@ Then move up one line.  Prefix arg means move that many 
lines."
   (tab-bar-tabs-set (delq tab (funcall tab-bar-tabs-function))))
 
 (defun tab-switcher-execute ()
-  "Delete window configurations marked with 
\\<tab-switcher-mode-map>\\[tab-switcher-delete] commands."
+  "Delete the marked window configurations.
+Use the \\<tab-switcher-mode-map>\\[tab-switcher-delete] commands
+to set those marks."
   (interactive)
   (save-excursion
     (goto-char (point-min))
@@ -2357,7 +2391,8 @@ with those specified by the selected window 
configuration."
    ((framep all-frames) (list all-frames))
    (t (list (selected-frame)))))
 
-(defun tab-bar-get-buffer-tab (buffer-or-name &optional all-frames 
ignore-current-tab all-tabs)
+(defun tab-bar-get-buffer-tab (buffer-or-name
+                               &optional all-frames ignore-current-tab 
all-tabs)
   "Return the tab that owns the window whose buffer is BUFFER-OR-NAME.
 BUFFER-OR-NAME may be a buffer or a buffer name, and defaults to
 the current buffer.
@@ -2533,7 +2568,7 @@ files will be visited."
         (progn
           (setq value (nreverse value))
           (switch-to-buffer-other-tab (car value))
-          (mapc 'switch-to-buffer (cdr value))
+          (mapc #'switch-to-buffer (cdr value))
           value)
       (switch-to-buffer-other-tab value))))
 
@@ -2575,26 +2610,26 @@ When `switch-to-buffer-obey-display-actions' is non-nil,
 
 ;;; Short aliases and keybindings
 
-(defalias 'tab-new             'tab-bar-new-tab)
-(defalias 'tab-new-to          'tab-bar-new-tab-to)
-(defalias 'tab-duplicate       'tab-bar-duplicate-tab)
-(defalias 'tab-detach          'tab-bar-detach-tab)
-(defalias 'tab-window-detach   'tab-bar-move-window-to-tab)
-(defalias 'tab-close           'tab-bar-close-tab)
-(defalias 'tab-close-other     'tab-bar-close-other-tabs)
-(defalias 'tab-close-group     'tab-bar-close-group-tabs)
-(defalias 'tab-undo            'tab-bar-undo-close-tab)
-(defalias 'tab-select          'tab-bar-select-tab)
-(defalias 'tab-switch          'tab-bar-switch-to-tab)
-(defalias 'tab-next            'tab-bar-switch-to-next-tab)
-(defalias 'tab-previous        'tab-bar-switch-to-prev-tab)
-(defalias 'tab-last            'tab-bar-switch-to-last-tab)
-(defalias 'tab-recent          'tab-bar-switch-to-recent-tab)
-(defalias 'tab-move            'tab-bar-move-tab)
-(defalias 'tab-move-to         'tab-bar-move-tab-to)
-(defalias 'tab-rename          'tab-bar-rename-tab)
-(defalias 'tab-group           'tab-bar-change-tab-group)
-(defalias 'tab-list            'tab-switcher)
+(defalias 'tab-new             #'tab-bar-new-tab)
+(defalias 'tab-new-to          #'tab-bar-new-tab-to)
+(defalias 'tab-duplicate       #'tab-bar-duplicate-tab)
+(defalias 'tab-detach          #'tab-bar-detach-tab)
+(defalias 'tab-window-detach   #'tab-bar-move-window-to-tab)
+(defalias 'tab-close           #'tab-bar-close-tab)
+(defalias 'tab-close-other     #'tab-bar-close-other-tabs)
+(defalias 'tab-close-group     #'tab-bar-close-group-tabs)
+(defalias 'tab-undo            #'tab-bar-undo-close-tab)
+(defalias 'tab-select          #'tab-bar-select-tab)
+(defalias 'tab-switch          #'tab-bar-switch-to-tab)
+(defalias 'tab-next            #'tab-bar-switch-to-next-tab)
+(defalias 'tab-previous        #'tab-bar-switch-to-prev-tab)
+(defalias 'tab-last            #'tab-bar-switch-to-last-tab)
+(defalias 'tab-recent          #'tab-bar-switch-to-recent-tab)
+(defalias 'tab-move            #'tab-bar-move-tab)
+(defalias 'tab-move-to         #'tab-bar-move-tab-to)
+(defalias 'tab-rename          #'tab-bar-rename-tab)
+(defalias 'tab-group           #'tab-bar-change-tab-group)
+(defalias 'tab-list            #'tab-switcher)
 
 (keymap-set tab-prefix-map "n"   #'tab-duplicate)
 (keymap-set tab-prefix-map "N"   #'tab-new-to)
diff --git a/lisp/term/xterm.el b/lisp/term/xterm.el
index 08e38c9a05..bcd3907d1e 100644
--- a/lisp/term/xterm.el
+++ b/lisp/term/xterm.el
@@ -571,6 +571,8 @@ Return the pasted text as a string."
                     (8 62  [?\C-\M->])
                     (8 63  [(control meta ??)])
 
+                    (3 32 [?\M-\s])
+
                     (2 9   [S-tab])
                     (2 13  [S-return])
 
diff --git a/lisp/textmodes/css-mode.el b/lisp/textmodes/css-mode.el
index b82886e397..822097a86d 100644
--- a/lisp/textmodes/css-mode.el
+++ b/lisp/textmodes/css-mode.el
@@ -1822,6 +1822,7 @@ Use `\\[fill-paragraph]' to reformat CSS declaration 
blocks.  It
 can also be used to fill comments.
 
 \\{css-mode-map}"
+  :syntax-table css-mode-syntax-table
   (when (treesit-ready-p 'css)
     ;; Borrowed from `css-mode'.
     (add-hook 'completion-at-point-functions
@@ -1839,11 +1840,6 @@ can also be used to fill comments.
                 '((selector comment query keyword)
                   (property constant string)
                   (error variable function operator bracket)))
-    ;; Tree-sitter-css, for whatever reason, cannot reliably return
-    ;; the captured nodes in a given range (it instead returns the
-    ;; nodes preceding range).  Before this is fixed in
-    ;; tree-sitter-css, use this heuristic as a temporary fix.
-    (setq-local treesit--font-lock-query-expand-range (cons 80 80))
     (setq-local imenu-create-index-function #'css--treesit-imenu)
     (setq-local which-func-functions nil)
     (treesit-major-mode-setup)))
diff --git a/lisp/textmodes/emacs-news-mode.el 
b/lisp/textmodes/emacs-news-mode.el
index ebb31da9cf..26f8f610ef 100644
--- a/lisp/textmodes/emacs-news-mode.el
+++ b/lisp/textmodes/emacs-news-mode.el
@@ -226,7 +226,7 @@ untagged NEWS entry."
         ;; Do manual references.
         (goto-char (point-min))
         (search-forward "\f" nil t)
-        (while (re-search-forward "\"\\(([a-z0-9]+)[ \n][^\"]\\{1,80\\}\\)\""
+        (while (re-search-forward "\"\\(([a-z0-9-]+)[ \n][^\"]\\{1,80\\}\\)\""
                                   nil t)
           (buttonize-region (match-beginning 1) (match-end 1)
                             (lambda (node) (info node))
diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el
index f815419ea4..126b3777f5 100644
--- a/lisp/textmodes/reftex.el
+++ b/lisp/textmodes/reftex.el
@@ -1004,10 +1004,13 @@ This enforces rescanning the buffer on next use."
                   reftex-section-levels))
 
     ;; Calculate the regular expressions
-    (let* (
-;          (wbol "\\(\\`\\|[\n\r]\\)[ \t]*")
-           (wbol "\\(^\\)%?[ \t]*") ; Need to keep the empty group because
-                                    ; match numbers are hard coded
+    (let* (;; (wbol "\\(\\`\\|[\n\r]\\)[ \t]*")
+           ;; Need to keep the empty group because match numbers are
+           ;; hard coded
+           (wbol (concat "\\(^\\)"
+                         (when (string-suffix-p ".dtx" (buffer-file-name) t)
+                           "%")
+                         "[ \t]*"))
            (label-re (concat "\\(?:"
                             (mapconcat #'identity reftex-label-regexps "\\|")
                             "\\)"))
diff --git a/lisp/textmodes/texinfo.el b/lisp/textmodes/texinfo.el
index 98672f42b3..24e93bf001 100644
--- a/lisp/textmodes/texinfo.el
+++ b/lisp/textmodes/texinfo.el
@@ -347,6 +347,8 @@ Subexpression 1 is what goes into the corresponding `@end' 
statement.")
 (defun texinfo-flymake (report-fn &rest _)
   "Texinfo checking for Flymake.
 
+It uses either \"makeinfo\" or \"texi2any\", in that order.
+
 REPORT-FN is the callback function."
   (let ((executable (or (executable-find "makeinfo")
                         (executable-find "texi2any")))
diff --git a/lisp/textmodes/toml-ts-mode.el b/lisp/textmodes/toml-ts-mode.el
new file mode 100644
index 0000000000..bca6a5e81a
--- /dev/null
+++ b/lisp/textmodes/toml-ts-mode.el
@@ -0,0 +1,187 @@
+;;; toml-ts-mode.el --- tree-sitter support for TOML  -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author     : Jostein Kjønigsen <jostein@kjonigsen.net>
+;; Maintainer : Jostein Kjønigsen <jostein@kjonigsen.net>
+;; Created    : December 2022
+;; Keywords   : toml languages tree-sitter
+
+;; 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:
+;;
+
+;;; Code:
+
+(require 'treesit)
+
+(declare-function treesit-parser-create "treesit.c")
+(declare-function treesit-induce-sparse-tree "treesit.c")
+(declare-function treesit-node-start "treesit.c")
+(declare-function treesit-node-child-by-field-name "treesit.c")
+
+(defcustom toml-ts-mode-indent-offset 2
+  "Number of spaces for each indentation step in `toml-ts-mode'."
+  :version "29.1"
+  :type 'integer
+  :safe 'integerp
+  :group 'toml)
+
+(defvar toml-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?_  "_"     table)
+    (modify-syntax-entry ?\\ "\\"    table)
+    (modify-syntax-entry ?=  "."     table)
+    (modify-syntax-entry ?\' "\""    table)
+    (modify-syntax-entry ?#  "<"   table)
+    (modify-syntax-entry ?\n "> b"  table)
+    (modify-syntax-entry ?\^m "> b" table)
+    table)
+  "Syntax table for `toml-ts-mode'.")
+
+(defvar toml-ts-mode--indent-rules
+  `((toml
+     ((node-is "]") parent-bol 0)
+     ((parent-is "string") parent-bol toml-ts-mode-indent-offset)
+     ((parent-is "array") parent-bol toml-ts-mode-indent-offset))))
+
+(defvar toml-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'toml
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
+
+   :language 'toml
+   :feature 'constant
+   '((boolean) @font-lock-constant-face)
+
+   :language 'toml
+   :feature 'delimiter
+   '((["="]) @font-lock-delimiter-face)
+
+   :language 'toml
+   :feature 'number
+   '([(integer) (float) (local_date) (local_date_time) (local_time)]
+     @font-lock-number-face)
+
+   :language 'toml
+   :feature 'string
+   '((string) @font-lock-string-face)
+
+   :language 'toml
+   :feature 'escape-sequence
+   :override t
+   '((escape_sequence) @font-lock-escape-face)
+
+   :language 'toml
+   :feature 'pair
+   :override t            ; Needed for overriding string face on keys.
+   '((bare_key) @font-lock-property-face
+     (quoted_key) @font-lock-property-face
+     (table ("[" @font-lock-bracket-face
+             (_) @font-lock-type-face
+             "]" @font-lock-bracket-face))
+     (table_array_element ("[[" @font-lock-bracket-face
+                           (_) @font-lock-type-face
+                           "]]" @font-lock-bracket-face))
+     (table (quoted_key) @font-lock-type-face)
+     (table (dotted_key (quoted_key)) @font-lock-type-face))
+
+   :language 'toml
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Font-lock settings for TOML.")
+
+(defun toml-ts-mode--get-table-name (node)
+  "Obtains the header-name for the associated tree-sitter `NODE'."
+  (if node
+      (treesit-node-text
+       (car (cdr (treesit-node-children node))))
+    "Root table"))
+
+(defun toml-ts-mode--imenu-1 (node)
+  "Helper for `toml-ts-mode--imenu'.
+Find string representation for NODE and set marker, then recurse
+the subtrees."
+  (let* ((ts-node (car node))
+         (subtrees (mapcan #'toml-ts-mode--imenu-1 (cdr node)))
+         (name (toml-ts-mode--get-table-name ts-node))
+         (marker (when ts-node
+                   (set-marker (make-marker)
+                               (treesit-node-start ts-node)))))
+    (cond
+     ((null ts-node) subtrees)
+     (subtrees
+      `((,name ,(cons name marker) ,@subtrees)))
+     (t
+      `((,name . ,marker))))))
+
+(defun toml-ts-mode--imenu ()
+  "Return Imenu alist for the current buffer."
+  (let* ((node (treesit-buffer-root-node))
+         (table-tree (treesit-induce-sparse-tree
+                      node "^table$" nil 1000))
+         (table-array-tree (treesit-induce-sparse-tree
+                            node "^table_array_element$" nil 1000))
+         (table-index (toml-ts-mode--imenu-1 table-tree))
+         (table-array-index (toml-ts-mode--imenu-1 table-array-tree)))
+    (append
+     (when table-index `(("Headers" . ,table-index)))
+     (when table-array-index `(("Arrays" . ,table-array-index))))))
+
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.toml\\'" . toml-ts-mode))
+
+;;;###autoload
+(define-derived-mode toml-ts-mode text-mode "TOML"
+  "Major mode for editing TOML, powered by tree-sitter."
+  :group 'toml-mode
+  :syntax-table toml-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'toml)
+    (treesit-parser-create 'toml)
+
+    ;; Comments
+    (setq-local comment-start "# ")
+    (setq-local comment-end "")
+
+    ;; Indent.
+    (setq-local treesit-simple-indent-rules toml-ts-mode--indent-rules)
+
+    ;; Navigation.
+    (setq-local treesit-defun-type-regexp
+                (rx (or "table" "table_array_element")))
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings toml-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '((comment)
+                  (constant number pair string)
+                  (escape-sequence)
+                  (delimiter error)))
+
+    ;; Imenu.
+    (setq-local imenu-create-index-function #'toml-ts-mode--imenu)
+    (setq-local which-func-functions nil) ;; Piggyback on imenu
+
+    (treesit-major-mode-setup)))
+
+(provide 'toml-ts-mode)
+
+;;; toml-ts-mode.el ends here
diff --git a/lisp/textmodes/yaml-ts-mode.el b/lisp/textmodes/yaml-ts-mode.el
new file mode 100644
index 0000000000..6ef6dabb3a
--- /dev/null
+++ b/lisp/textmodes/yaml-ts-mode.el
@@ -0,0 +1,151 @@
+;;; yaml-ts-mode.el --- tree-sitter support for YAML  -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author     : Randy Taylor <dev@rjt.dev>
+;; Maintainer : Randy Taylor <dev@rjt.dev>
+;; Created    : December 2022
+;; Keywords   : yaml languages tree-sitter
+
+;; 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:
+;;
+
+;;; Code:
+
+(require 'treesit)
+
+(declare-function treesit-parser-create "treesit.c")
+
+(defvar yaml-ts-mode--syntax-table
+  (let ((table (make-syntax-table)))
+    (modify-syntax-entry ?#  "<"  table)
+    (modify-syntax-entry ?\n ">"  table)
+    (modify-syntax-entry ?&  "."  table)
+    (modify-syntax-entry ?*  "."  table)
+    (modify-syntax-entry ?\( "."  table)
+    (modify-syntax-entry ?\) "."  table)
+    (modify-syntax-entry ?\' "\"" table)
+    table)
+  "Syntax table for `yaml-ts-mode'.")
+
+(defvar yaml-ts-mode--font-lock-settings
+  (treesit-font-lock-rules
+   :language 'yaml
+   :feature 'bracket
+   '((["[" "]" "{" "}"]) @font-lock-bracket-face)
+
+   :language 'yaml
+   :feature 'comment
+   '((comment) @font-lock-comment-face)
+
+   :language 'yaml
+   :feature 'constant
+   '([(boolean_scalar)
+      (null_scalar)
+      (reserved_directive)
+      (tag_directive)
+      (yaml_directive)] @font-lock-constant-face)
+
+   :language 'yaml
+   :feature 'delimiter
+   '((["," ":" "-" ">" "?" "|"]) @font-lock-delimiter-face)
+
+   :language 'yaml
+   :feature 'misc-punctuation
+   '((["---" "..." "&" "*"]) @font-lock-misc-punctuation-face)
+
+   :language 'yaml
+   :feature 'number
+   '([(float_scalar) (integer_scalar)] @font-lock-number-face)
+
+   :language 'yaml
+   :feature 'type
+   '([(alias_name) (anchor_name) (tag)] @font-lock-type-face)
+
+   :language 'yaml
+   :feature 'string
+   :override t
+   '([(block_scalar)
+      (double_quote_scalar)
+      (single_quote_scalar)
+      (string_scalar)] @font-lock-string-face)
+
+   :language 'yaml
+   :feature 'escape-sequence
+   :override t
+   '((escape_sequence) @font-lock-escape-face)
+
+   :language 'yaml
+   :feature 'property
+   :override t
+   '((block_mapping_pair
+      key: (flow_node (plain_scalar (string_scalar) @font-lock-property-face)))
+     (block_mapping_pair
+      key: (flow_node
+            [(double_quote_scalar) (single_quote_scalar)] 
@font-lock-property-face))
+     (flow_mapping
+      (_ key: (flow_node (plain_scalar (string_scalar) 
@font-lock-property-face))))
+     (flow_mapping
+      (_ key:
+         (flow_node
+          [(double_quote_scalar) (single_quote_scalar)] 
@font-lock-property-face)))
+     (flow_sequence
+      (_ key: (flow_node (plain_scalar (string_scalar) 
@font-lock-property-face))))
+     (flow_sequence
+      (_ key:
+         (flow_node
+          [(double_quote_scalar) (single_quote_scalar)] 
@font-lock-property-face))))
+
+   :language 'yaml
+   :feature 'error
+   :override t
+   '((ERROR) @font-lock-warning-face))
+  "Tree-sitter font-lock settings for `yaml-ts-mode'.")
+
+;;;###autoload
+(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))
+
+;;;###autoload
+(define-derived-mode yaml-ts-mode text-mode "YAML"
+  "Major mode for editing YAML, powered by tree-sitter."
+  :group 'yaml
+  :syntax-table yaml-ts-mode--syntax-table
+
+  (when (treesit-ready-p 'yaml)
+    (treesit-parser-create 'yaml)
+
+    ;; Comments.
+    (setq-local comment-start "# ")
+    (setq-local comment-end "")
+
+    ;; Indentation.
+    (setq-local indent-tabs-mode nil)
+
+    ;; Font-lock.
+    (setq-local treesit-font-lock-settings yaml-ts-mode--font-lock-settings)
+    (setq-local treesit-font-lock-feature-list
+                '((comment)
+                  (string type)
+                  (constant escape-sequence number property)
+                  (bracket delimiter error misc-punctuation)))
+
+    (treesit-major-mode-setup)))
+
+(provide 'yaml-ts-mode)
+
+;;; yaml-ts-mode.el ends here
diff --git a/lisp/transient.el b/lisp/transient.el
index 1cab697eec..01c492c68c 100644
--- a/lisp/transient.el
+++ b/lisp/transient.el
@@ -2203,7 +2203,7 @@ value.  Otherwise return CHILDREN as is."
     (unless abort-only
       (setq post-command
             (lambda () "@transient--delay-post-command"
-              (let ((act (and (not (eq (this-command-keys-vector) []))
+              (let ((act (and (not (equal (this-command-keys-vector) []))
                               (or (eq this-command command)
                                   ;; `execute-extended-command' was
                                   ;; used to call another command
@@ -2241,7 +2241,7 @@ value.  Otherwise return CHILDREN as is."
   (transient--debug 'post-command)
   (transient--with-emergency-exit
     (cond
-     ((and (eq (this-command-keys-vector) [])
+     ((and (equal (this-command-keys-vector) [])
            (= (minibuffer-depth)
               (1+ transient--minibuffer-depth)))
       (transient--suspend-override)
diff --git a/lisp/treesit.el b/lisp/treesit.el
index eee6eee0c7..1f366807ce 100644
--- a/lisp/treesit.el
+++ b/lisp/treesit.el
@@ -545,12 +545,7 @@ This should be a cons cell (START . END).  When fontifying 
a
 buffer, Emacs will move the start of the query range backward by
 START amount, and the end of the query range by END amount.  Both
 START and END should be positive integers or 0.  This doesn't
-affect the fontified range.
-
-Sometimes, querying on some parser with a restricted range
-returns nodes not in that range but before it, which breaks
-fontification.  Major modes can adjust this variable as a
-temporarily fix.")
+affect the fontified range.")
 
 (defvar-local treesit-font-lock-feature-list nil
   "A list of lists of feature symbols.
@@ -838,21 +833,28 @@ The range is between START and END."
         (nreverse result))
     (list node)))
 
-(defun treesit--children-covering-range-recurse (node start end threshold)
+(defun treesit--children-covering-range-recurse
+    (node start end threshold &optional limit)
   "Return a list of children of NODE covering a range.
+
 Recursively go down the parse tree and collect children, until
 all nodes in the returned list are smaller than THRESHOLD.  The
-range is between START and END."
+range is between START and END.
+
+LIMIT is the recursion limit, which defaults to 100."
   (let* ((child (treesit-node-first-child-for-pos node start))
+         (limit (or limit 100))
          result)
-    (while (and child (<= (treesit-node-start child) end))
+    ;; If LIMIT is exceeded, we are probably seeing the erroneously
+    ;; tall tree, in that case, just give up.
+    (while (and (> limit 0) child (<= (treesit-node-start child) end))
       ;; If child still too large, recurse down.  Otherwise collect
       ;; child.
       (if (> (- (treesit-node-end child)
                 (treesit-node-start child))
              threshold)
           (dolist (r (treesit--children-covering-range-recurse
-                      child start end threshold))
+                      child start end threshold (1- limit)))
             (push r result))
         (push child result))
       (setq child (treesit-node-next-sibling child)))
@@ -893,6 +895,12 @@ detail.")
 ;; top-level nodes and query them.  This ensures that querying is fast
 ;; everywhere else, except for the problematic region.
 ;;
+;; Some other time the source file has a top-level node that contains
+;; a huge number of children (say, 10k children), querying that node
+;; is also very slow, so instead of getting the top-level node, we
+;; recursively go down the tree to find nodes that cover the region
+;; but are reasonably small.
+;;
 ;; 3. It is possible to capture a node that's completely outside the
 ;; region between START and END: as long as the whole pattern
 ;; intersects the region, all the captured nodes in that pattern are
@@ -922,8 +930,8 @@ If LOUDLY is non-nil, display some debugging information."
         ;; If we run into problematic files, use the "fast mode" to
         ;; try to recover.  See comment #2 above for more explanation.
         (when treesit--font-lock-fast-mode
-          (setq nodes (treesit--children-covering-range
-                       (car nodes) start end)))
+          (setq nodes (treesit--children-covering-range-recurse
+                       (car nodes) start end (* 4 jit-lock-chunk-size))))
 
         ;; Query each node.
         (dolist (sub-node nodes)
@@ -1039,7 +1047,6 @@ See `treesit-simple-indent-presets'.")
                        (or (null node-index-max)
                            (<= (treesit-node-index node)
                                node-index-max))))))
-        ;; TODO: Document if genuinely useful.
         (cons 'n-p-gp
               (lambda (node-t parent-t grand-parent-t)
                 (lambda (node parent &rest _)
@@ -1100,12 +1107,6 @@ See `treesit-simple-indent-presets'.")
                   (re-search-forward comment-start-skip)
                   (skip-syntax-backward "-")
                   (point))))
-        (cons 'comment-start-skip
-              (lambda (_n parent &rest _)
-                (save-excursion
-                  (goto-char (treesit-node-start parent))
-                  (re-search-forward comment-start-skip)
-                  (point))))
         ;; TODO: Document.
         (cons 'grand-parent
               (lambda (_n parent &rest _)
@@ -1180,6 +1181,10 @@ no-node
 
     Checks that NODE's type matches regexp TYPE.
 
+\(n-p-gp NODE-TYPE PARENT-TYPE GRANDPARENT-TYPE)
+
+    Checks that NODE, its parent, and its grandparent's type.
+
 \(query QUERY)
 
     Queries PARENT with QUERY, and checks if NODE is
@@ -1222,14 +1227,9 @@ point-min
 
 comment-start
 
-    Returns the position after a match for `treesit-comment-start'.
-    Assumes PARENT is a comment node.
-
-comment-start-skip
-
-    Goes to the position that comment-start would return, skips
-    whitespace after that, and returns the resulting position.
-    Assumes PARENT is a comment node.")
+    Goes to the position that `comment-start-skip' would return,
+    skips whitespace backwards, and returns the resulting
+    position.  Assumes PARENT is a comment node.")
 
 (defun treesit--simple-indent-eval (exp)
   "Evaluate EXP.
@@ -1561,75 +1561,284 @@ BACKWARD and ALL are the same as in 
`treesit-search-forward'."
   "A regexp that matches the node type of defun nodes.
 For example, \"(function|class)_definition\".
 
+Sometimes not all nodes matched by the regexp are valid defuns.
+In that case, set this variable to a cons cell of the
+form (REGEXP . FILTER), where FILTER is a function that takes a
+node (the matched node) and returns t if node is valid, or nil
+for invalid node.
+
 This is used by `treesit-beginning-of-defun' and friends.")
 
-(defvar-local treesit-defun-prefer-top-level nil
-  "When non-nil, Emacs prefers top-level defun.
-
-In some languages, a defun could be nested in another one.
-Normally Emacs stops at the first defun it encounters.  If this
-variable's value is t, Emacs tries to find the top-level defun,
-and ignores nested ones.
-
-This variable can also be a list of cons cells of the
-form (FROM . TO), where FROM and TO are tree-sitter node type
-regexps.  When Emacs finds a defun node whose type matches any of
-the FROM regexps in the list, it then tries to find a
-higher-level node matching the corresponding TO regexp.")
-
-(defun treesit--defun-maybe-top-level (node)
-  "Maybe return the top-level equivalent of NODE.
-For the detailed semantic see `treesit-defun-prefer-top-level'."
-  (pcase treesit-defun-prefer-top-level
-    ('nil node)
-    ('t (or (treesit-node-top-level
-             node treesit-defun-type-regexp)
-            node))
-    ((pred consp)
-     (cl-loop
-      for con in treesit-defun-prefer-top-level
-      for from = (car con)
-      for to = (cdr con)
-      if (string-match-p from (treesit-node-type node))
-      return (or (treesit-node-top-level node to)
-                 node)
-      finally return node))))
+(defvar-local treesit-defun-tactic 'nested
+  "Determines how does Emacs treat nested defuns.
+If the value is `top-level', Emacs only moves across top-level
+defuns, if the value is `nested', Emacs recognizes nested defuns.")
+
+(defvar-local treesit-defun-skipper #'treesit-default-defun-skipper
+  "A function called after tree-sitter navigation moved a step.
+
+It is called with no arguments.  By default, this function tries
+to move to the beginning of a line, either by moving to the empty
+newline after a defun, or the beginning of a defun.
+
+If the value is nil, no skipping is performed.")
 
 (defun treesit-beginning-of-defun (&optional arg)
-  "Tree-sitter `beginning-of-defun' function.
-ARG is the same as in `beginning-of-defun'."
-  (let ((arg (or arg 1))
-        (node (treesit-node-at (point))))
-    (if (> arg 0)
-        ;; Go backward.
-        (while (and (> arg 0)
-                    (setq node (treesit-search-forward-goto
-                                node treesit-defun-type-regexp t t)))
-          (setq node (treesit--defun-maybe-top-level node))
-          (setq arg (1- arg)))
-      ;; Go forward.
-      (while (and (< arg 0)
-                  (setq node (treesit-search-forward-goto
-                              node treesit-defun-type-regexp)))
-        (setq node (treesit--defun-maybe-top-level node))
-        (setq arg (1+ arg))))
-    (when node
-      (goto-char (treesit-node-start node))
-      t)))
-
-(defun treesit-end-of-defun ()
-  "Tree-sitter `end-of-defun' function."
-  ;; Why not simply get the largest node at point: when point is at
-  ;; (point-min), that gives us the root node.
-  (let* ((node (treesit-search-forward
-                (treesit-node-at (point)) treesit-defun-type-regexp t t))
-         (top (treesit--defun-maybe-top-level node)))
-    ;; Technically `end-of-defun' should only call this function when
-    ;; point is at the beginning of a defun, so TOP should always be
-    ;; non-nil, but things happen, and we want to be safe, so check
-    ;; for TOP anyway.
-    (when top
-      (goto-char (treesit-node-end top)))))
+  "Move backward to the beginning of a defun.
+
+With argument ARG, do it that many times.  Negative ARG means
+move forward to the ARGth following beginning of defun.
+
+If search is successful, return t, otherwise return nil.
+
+This is a tree-sitter equivalent of `beginning-of-defun'.
+Behavior of this function depends on `treesit-defun-type-regexp'
+and `treesit-defun-skipper'."
+  (interactive "^p")
+  (when-let* ((arg (or arg 1))
+              (dest (treesit--navigate-defun (point) (- arg) 'beg)))
+    (goto-char dest)
+    (when treesit-defun-skipper
+      (funcall treesit-defun-skipper))
+    t))
+
+(defun treesit-end-of-defun (&optional arg _)
+  "Move forward to next end of defun.
+
+With argument ARG, do it that many times.
+Negative argument -N means move back to Nth preceding end of defun.
+
+This is a tree-sitter equivalent of `end-of-defun'.  Behavior of
+this function depends on `treesit-defun-type-regexp' and
+`treesit-defun-skipper'."
+  (interactive "^p\nd")
+  (when-let* ((arg (or arg 1))
+              (dest (treesit--navigate-defun (point) arg 'end)))
+    (goto-char dest)
+    (when treesit-defun-skipper
+      (funcall treesit-defun-skipper))))
+
+(defvar-local treesit-text-type-regexp "\\`comment\\'"
+  "A regexp that matches the node type of textual nodes.
+
+A textual node is a node that is not normal code, such as
+comments and multiline string literals.  For example,
+\"(line|block)_comment\" in the case of a comment, or
+\"text_block\" in the case of a string.  This is used by
+`prog-fill-reindent-defun' and friends.")
+
+(defun treesit-default-defun-skipper ()
+  "Skips spaces after navigating a defun.
+This function tries to move to the beginning of a line, either by
+moving to the empty newline after a defun, or to the beginning of
+the current line if the beginning of the defun is indented."
+  (cond ((and (looking-at (rx (* (or " " "\\t")) "\n"))
+              (not (looking-at (rx bol))))
+         (goto-char (match-end 0)))
+        ((save-excursion
+           (skip-chars-backward " \t")
+           (eq (point) (line-beginning-position)))
+         (goto-char (line-beginning-position)))))
+
+;; prev-sibling:
+;; 1. end-of-node before pos
+;; 2. highest such node
+;;
+;; next-sibling:
+;; 1. beg-of-node after pos
+;; 2. highest such node
+;;
+;; parent:
+;; 1. node covers pos
+;; 2. smallest such node
+(defun treesit--defuns-around (pos regexp &optional pred)
+  "Return the previous, next, and parent defun around POS.
+
+Return a list of (PREV NEXT PARENT), where PREV and NEXT are
+previous and next sibling defuns around POS, and PARENT is the
+parent defun surrounding POS.  All of three could be nil if no
+sound defun exists.
+
+REGEXP and PRED are the same as in `treesit-defun-type-regexp'."
+  (let* ((node (treesit-node-at pos))
+         ;; NODE-BEFORE/AFTER = NODE when POS is completely in NODE,
+         ;; but if not, that means point could be in between two
+         ;; defun, in that case we want to use a node that's actually
+         ;; before/after point.
+         (node-before (if (>= (treesit-node-start node) pos)
+                          (treesit-search-forward-goto node "" t t t)
+                        node))
+         (node-after (if (<= (treesit-node-end node) pos)
+                         (treesit-search-forward-goto node "" nil nil t)
+                       node))
+         (result (list nil nil nil))
+         (pred (or pred (lambda (_) t))))
+    ;; 1. Find previous and next sibling defuns.
+    (cl-loop
+     for idx from 0 to 1
+     for node in (list node-before node-after)
+     for backward in '(t nil)
+     for pos-pred in (list (lambda (n) (<= (treesit-node-end n) pos))
+                           (lambda (n) (>= (treesit-node-start n) pos)))
+     ;; If point is inside a defun, our process below will never
+     ;; return a next/prev sibling outside of that defun, effectively
+     ;; any prev/next sibling is locked inside the smallest defun
+     ;; covering point, which is the correct behavior.  That's because
+     ;; when there exists a defun that covers point,
+     ;; `treesit-search-forward' will first reach that defun, after
+     ;; that we only go upwards in the tree, so other defuns outside
+     ;; of the covering defun is never reached.  (Don't use
+     ;; `treesit-search-forward-goto' as it breaks when NODE-AFTER is
+     ;; the last token of a parent defun: it will skip the parent
+     ;; defun because it wants to ensure progress.)
+     do (cl-loop for cursor = (when node
+                                (save-excursion
+                                  (treesit-search-forward
+                                   node regexp backward backward)))
+                 then (treesit-node-parent cursor)
+                 while cursor
+                 if (and (string-match-p
+                          regexp (treesit-node-type cursor))
+                         (funcall pred cursor)
+                         (funcall pos-pred cursor))
+                 do (setf (nth idx result) cursor)))
+    ;; 2. Find the parent defun.
+    (setf (nth 2 result)
+          (cl-loop for cursor = (or (nth 0 result)
+                                    (nth 1 result)
+                                    node)
+                   then (treesit-node-parent cursor)
+                   while cursor
+                   if (and (string-match-p
+                            regexp (treesit-node-type cursor))
+                           (funcall pred cursor)
+                           (not (member cursor result)))
+                   return cursor))
+    result))
+
+(defun treesit--top-level-defun (node regexp &optional pred)
+  "Return the top-level parent defun of NODE.
+REGEXP and PRED are the same as in `treesit-defun-type-regexp'."
+  (let* ((pred (or pred (lambda (_) t))))
+    ;; `treesit-search-forward-goto' will make sure the matched node
+    ;; is before POS.
+    (cl-loop for cursor = node
+             then (treesit-node-parent cursor)
+             while cursor
+             if (and (string-match-p
+                      regexp (treesit-node-type cursor))
+                     (funcall pred cursor))
+             do (setq node cursor))
+    node))
+
+;; The basic idea for nested defun navigation is that we first try to
+;; move across sibling defuns in the same level, if no more siblings
+;; exist, we move to parents's beg/end, rinse and repeat.  We never
+;; move into a defun, only outwards.
+;;
+;; Let me describe roughly what does this function do: there are four
+;; possible operations: prev-beg, next-end, prev-end, next-beg, and
+;; each of (prev-sibling next-sibling and parent) could exist or not
+;; exist.  So there are 4 times 8 = 32 situations.
+;;
+;; I'll only describe the situation when we go backward (prev-beg &
+;; prev-end), and consider only prev-sibling & parent. Deriving the
+;; reverse situations is left as an exercise for the reader.
+;;
+;; prev-beg (easy case):
+;; 1. prev-sibling or parent exists
+;;    -> go the prev-sibling/parent's beg
+;;
+;; prev-end (tricky):
+;; 1. prev-sibling exists
+;;    -> If you think about it, we are already at prev-sibling's end!
+;;       So we need to go one step further, either to
+;;       prev-prev-sibling's end, or parent's prev-sibling's end, etc.
+;; 2. prev-sibling is nil but parent exists
+;;    -> Obviously we don't want to go to parent's end, instead, we
+;;       want to go to parent's prev-sibling's end.  Again, we recurse
+;;       in the function to do that.
+(defun treesit--navigate-defun (pos arg side &optional recursing)
+  "Navigate defun ARG steps from POS.
+
+If ARG is positive, move forward that many steps, if negative,
+move backward.  If SIDE is `beg', stop at the beginning of a
+defun, if SIDE is `end', stop at the end.
+
+This function doesn't actually move point, it just returns the
+position it would move to.  If there aren't enough defuns to move
+across, return nil.
+
+RECURSING is an internal parameter, if non-nil, it means this
+function is called recursively."
+  (pcase-let*
+      ((counter (abs arg))
+       (`(,regexp . ,pred)
+        (if (consp treesit-defun-type-regexp)
+            treesit-defun-type-regexp
+          (cons treesit-defun-type-regexp nil)))
+       ;; Move POS to the beg/end of NODE.  If NODE is nil, terminate.
+       ;; Return the position we moved to.
+       (advance (lambda (node)
+                  (let ((dest (pcase side
+                                ('beg (treesit-node-start node))
+                                ('end (treesit-node-end node)))))
+                    (if (null dest)
+                        (throw 'term nil)
+                      dest)))))
+    (catch 'term
+      (while (> counter 0)
+        (pcase-let
+            ((`(,prev ,next ,parent)
+              (treesit--defuns-around pos regexp pred)))
+          ;; When PARENT is nil, nested and top-level are the same, if
+          ;; there is a PARENT, make PARENT to be the top-level parent
+          ;; and pretend there is no nested PREV and NEXT.
+          (when (and (eq treesit-defun-tactic 'top-level)
+                     parent)
+            (setq parent (treesit--top-level-defun
+                          parent regexp pred)
+                  prev nil
+                  next nil))
+          ;; Move...
+          (if (> arg 0)
+              ;; ...forward.
+              (if (and (eq side 'beg)
+                       ;; Should we skip the defun (recurse)?
+                       (cond (next (not recursing)) ; [1] (see below)
+                             (parent t) ; [2]
+                             (t nil)))
+                  ;; Special case: go to next beg-of-defun.  Set POS
+                  ;; to the end of next-sib/parent defun, and run one
+                  ;; more step.  If there is a next-sib defun, we only
+                  ;; need to recurse once, so we don't need to recurse
+                  ;; if we are already recursing [1]. If there is no
+                  ;; next-sib but a parent, keep stepping out
+                  ;; (recursing) until we got out of the parents until
+                  ;; (1) there is a next sibling defun, or (2) no more
+                  ;; parents [2].
+                  (setq pos (or (treesit--navigate-defun
+                                 (treesit-node-end (or next parent))
+                                 1 'beg t)
+                                (throw 'term nil)))
+                ;; Normal case.
+                (setq pos (funcall advance (or next parent))))
+            ;; ...backward.
+            (if (and (eq side 'end)
+                     (cond (prev (not recursing))
+                           (parent t)
+                           (t nil)))
+                ;; Special case: go to prev end-of-defun.
+                (setq pos (or (treesit--navigate-defun
+                               (treesit-node-start (or prev parent))
+                               -1 'end t)
+                              (throw 'term nil)))
+              ;; Normal case.
+              (setq pos (funcall advance (or prev parent)))))
+          ;; A successful step! Decrement counter.
+          (cl-decf counter))))
+    ;; Counter equal to 0 means we successfully stepped ARG steps.
+    (if (eq counter 0) pos nil)))
 
 ;;; Activating tree-sitter
 
@@ -1712,8 +1921,10 @@ before calling this function."
     (setq-local indent-region-function #'treesit-indent-region))
   ;; Navigation.
   (when treesit-defun-type-regexp
-    (setq-local beginning-of-defun-function #'treesit-beginning-of-defun)
-    (setq-local end-of-defun-function #'treesit-end-of-defun)))
+    (keymap-set (current-local-map) "<remap> <beginning-of-defun>"
+                #'treesit-beginning-of-defun)
+    (keymap-set (current-local-map) "<remap> <end-of-defun>"
+                #'treesit-end-of-defun)))
 
 ;;; Debugging
 
@@ -1737,9 +1948,9 @@ in `treesit-parser-list'."
                    collect node))
          (largest-node (car (last node-list)))
          (parent (treesit-node-parent largest-node))
-         ;; node-list-acending contains all the node bottom-up, then
+         ;; node-list-ascending contains all the node bottom-up, then
          ;; the parent.
-         (node-list-acending
+         (node-list-ascending
           (if (null largest-node)
               ;; If there are no nodes that start at point, just show
               ;; the node at point and its parent.
@@ -1750,7 +1961,7 @@ in `treesit-parser-list'."
          (name ""))
     ;; We draw nodes like (parent field-name: (node)) recursively,
     ;; so it could be (node1 field-name: (node2 field-name: (node3))).
-    (dolist (node node-list-acending)
+    (dolist (node node-list-ascending)
       (setq
        name
        (concat
@@ -1827,10 +2038,23 @@ to the offending pattern and highlight the pattern."
              (goto-char (point-min))
              (insert (format "%s: %d\n" message start))
              (forward-char start)))
-         (pop-to-buffer buf))))))
+         (pop-to-buffer buf)
+         (view-mode))))))
 
 ;;; Explorer
 
+(defface treesit-explorer-anonymous-node
+  (let ((display t)
+        (atts '(:inherit shadow)))
+    `((,display . ,atts)))
+  "Face for anonymous nodes in tree-sitter explorer.")
+
+(defface treesit-explorer-field-name
+  (let ((display t)
+        (atts nil))
+    `((,display . ,atts)))
+  "Face for field names in tree-sitter explorer.")
+
 (defvar-local treesit--explorer-buffer nil
   "Buffer used to display the syntax tree.")
 
@@ -2009,7 +2233,8 @@ leaves point at the end of the last line of NODE."
     ;; draw everything in one line, other wise draw field name and the
     ;; rest of the node in two lines.
     (when field-name
-      (insert field-name ": ")
+      (insert (propertize (concat field-name ": ")
+                          'face 'treesit-explorer-field-name))
       (when (and children (not all-children-inline))
         (insert "\n")
         (indent-to-column (1+ before-field-column))))
@@ -2068,7 +2293,7 @@ leaves point at the end of the last line of NODE."
       (overlay-put ov 'treesit-node node)
       (overlay-put ov 'evaporate t)
       (when (not named)
-        (overlay-put ov 'face 'shadow)))))
+        (overlay-put ov 'face 'treesit-explorer-anonymous-node)))))
 
 (define-derived-mode treesit--explorer-tree-mode special-mode
   "TS Explorer"
@@ -2087,7 +2312,7 @@ window."
         (unless (buffer-live-p treesit--explorer-buffer)
           (setq-local treesit--explorer-buffer
                       (get-buffer-create
-                       (format "*tree-sitter playground for %s*"
+                       (format "*tree-sitter explorer for %s*"
                                (buffer-name))))
           (setq-local treesit--explorer-language
                       (intern (completing-read
diff --git a/lisp/use-package/bind-key.el b/lisp/use-package/bind-key.el
new file mode 100644
index 0000000000..c3890c4d0a
--- /dev/null
+++ b/lisp/use-package/bind-key.el
@@ -0,0 +1,569 @@
+;;; bind-key.el --- A simple way to manage personal keybindings  -*- 
lexical-binding: t; -*-
+
+;; Copyright (c) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+;; Created: 16 Jun 2012
+;; Version: 2.4.1
+;; Package-Requires: ((emacs "24.3"))
+;; Keywords: keys keybinding config dotemacs extensions
+;; URL: https://github.com/jwiegley/use-package
+
+;; 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:
+
+;; If you have lots of keybindings set in your init file, it can be
+;; hard to know which ones you haven't set yet, and which may now be
+;; overriding some new default in a new Emacs version.  This module
+;; aims to solve that problem.
+;;
+;; Bind keys as follows in your init file:
+;;
+;;   (bind-key "C-c x" 'my-ctrl-c-x-command)
+;;
+;; If the keybinding argument is a vector, it is passed straight to
+;; `define-key', so remapping a key with `[remap COMMAND]' works as
+;; expected:
+;;
+;;   (bind-key [remap original-ctrl-c-x-command] 'my-ctrl-c-x-command)
+;;
+;; If you want the keybinding to override all minor modes that may also bind
+;; the same key, use the `bind-key*' form:
+;;
+;;   (bind-key* "<C-return>" 'other-window)
+;;
+;; If you want to rebind a key only in a particular keymap, use:
+;;
+;;   (bind-key "C-c x" 'my-ctrl-c-x-command some-other-mode-map)
+;;
+;; To unbind a key within a keymap (for example, to stop your favorite major
+;; mode from changing a binding that you don't want to override everywhere),
+;; use `unbind-key':
+;;
+;;   (unbind-key "C-c x" some-other-mode-map)
+;;
+;; To bind multiple keys at once, or set up a prefix map, a `bind-keys' macro
+;; is provided.  It accepts keyword arguments, please see its documentation
+;; for a detailed description.
+;;
+;; To add keys into a specific map, use :map argument
+;;
+;;    (bind-keys :map dired-mode-map
+;;               ("o" . dired-omit-mode)
+;;               ("a" . some-custom-dired-function))
+;;
+;; To set up a prefix map, use `:prefix-map' and `:prefix' arguments (both are
+;; required)
+;;
+;;    (bind-keys :prefix-map my-customize-prefix-map
+;;               :prefix "C-c c"
+;;               ("f" . customize-face)
+;;               ("v" . customize-variable))
+;;
+;; You can combine all the keywords together.  Additionally,
+;; `:prefix-docstring' can be specified to set documentation of created
+;; `:prefix-map' variable.
+;;
+;; To bind multiple keys in a `bind-key*' way (to be sure that your bindings
+;; will not be overridden by other modes), you may use `bind-keys*' macro:
+;;
+;;    (bind-keys*
+;;     ("C-o" . other-window)
+;;     ("C-M-n" . forward-page)
+;;     ("C-M-p" . backward-page))
+;;
+;; After Emacs loads, you can see a summary of all your personal keybindings
+;; currently in effect with this command:
+;;
+;;   M-x describe-personal-keybindings
+;;
+;; This display will tell you if you've overridden a default keybinding, and
+;; what the default was.  Also, it will tell you if the key was rebound after
+;; your binding it with `bind-key', and what it was rebound it to.
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'easy-mmode)
+
+(defgroup bind-key nil
+  "A simple way to manage personal keybindings."
+  :group 'keyboard
+  :group 'convenience
+  :link '(emacs-commentary-link :tag "Commentary" "bind-key.el")
+  :version "29.1")
+
+(defcustom bind-key-column-widths '(18 . 40)
+  "Width of columns in `describe-personal-keybindings'."
+  :type '(cons integer integer)
+  :group 'bind-key)
+
+(defcustom bind-key-segregation-regexp
+  "\\`\\(\\(C-[chx] \\|M-[gso] \\)\\([CM]-\\)?\\|.+-\\)"
+  "Regexp used by \\[describe-personal-keybindings] to divide key sets."
+  :type 'regexp
+  :group 'bind-key)
+
+(defcustom bind-key-describe-special-forms nil
+  "If non-nil, extract docstrings from lambdas, closures and keymaps if 
possible."
+  :type 'boolean
+  :group 'bind-key)
+
+;; Create override-global-mode to force key remappings
+
+(defvar override-global-map (make-keymap)
+  "Keymap for `override-global-mode'.")
+
+(define-minor-mode override-global-mode
+  "A minor mode for allowing keybindings to override other modes.
+The main purpose of this mode is to simplify bindings keys in
+such a way that they take precedence over other modes.
+
+To achieve this, the keymap `override-global-map' is added to
+`emulation-mode-map-alists', which makes it take precedence over
+keymaps in `minor-mode-map-alist'.  Thereby, key bindings get an
+even higher precedence than global key bindings defined with
+`keymap-global-set' (or, in Emacs 28 or older, `global-set-key').
+
+The macro `bind-key*' (which see) provides a convenient way to
+add keys to that keymap."
+  :init-value t
+  :lighter "")
+
+;; the keymaps in `emulation-mode-map-alists' take precedence over
+;; `minor-mode-map-alist'
+(add-to-list 'emulation-mode-map-alists
+             `((override-global-mode . ,override-global-map)))
+
+(defvar personal-keybindings nil
+  "List of bindings performed by `bind-key'.
+
+Elements have the form ((KEY . [MAP]) CMD ORIGINAL-CMD)")
+
+;;;###autoload
+(defmacro bind-key (key-name command &optional keymap predicate)
+  "Bind KEY-NAME to COMMAND in KEYMAP (`global-map' if not passed).
+
+KEY-NAME may be a vector, in which case it is passed straight to
+`define-key'.  Or it may be a string to be interpreted as
+spelled-out keystrokes, e.g., \"C-c C-z\".  See the documentation
+of `edmacro-mode' for details.
+
+COMMAND must be an interactive function or lambda form.
+
+KEYMAP, if present, should be a keymap variable or symbol.
+For example:
+
+  (bind-key \"M-h\" #\\='some-interactive-function my-mode-map)
+
+  (bind-key \"M-h\" #\\='some-interactive-function \\='my-mode-map)
+
+If PREDICATE is non-nil, it is a form evaluated to determine when
+a key should be bound. It must return non-nil in such cases.
+Emacs can evaluate this form at any time that it does redisplay
+or operates on menu data structures, so you should write it so it
+can safely be called at any time."
+  (let ((namevar (make-symbol "name"))
+        (keyvar (make-symbol "key"))
+        (kmapvar (make-symbol "kmap"))
+        (kdescvar (make-symbol "kdesc"))
+        (bindingvar (make-symbol "binding")))
+    `(let* ((,namevar ,key-name)
+            (,keyvar ,(if (stringp key-name) (read-kbd-macro key-name)
+                        `(if (vectorp ,namevar) ,namevar
+                           (read-kbd-macro ,namevar))))
+            (,kmapvar (or (if (and ,keymap (symbolp ,keymap))
+                              (symbol-value ,keymap) ,keymap)
+                          global-map))
+            (,kdescvar (cons (if (stringp ,namevar) ,namevar
+                               (key-description ,namevar))
+                             (if (symbolp ,keymap) ,keymap (quote ,keymap))))
+            (,bindingvar (lookup-key ,kmapvar ,keyvar)))
+       (let ((entry (assoc ,kdescvar personal-keybindings))
+             (details (list ,command
+                            (unless (numberp ,bindingvar)
+                              ,bindingvar))))
+         (if entry
+             (setcdr entry details)
+           (add-to-list 'personal-keybindings (cons ,kdescvar details))))
+       ,(if predicate
+            `(define-key ,kmapvar ,keyvar
+               '(menu-item "" nil :filter (lambda (&optional _)
+                                            (when ,predicate
+                                              ,command))))
+          `(define-key ,kmapvar ,keyvar ,command)))))
+
+;;;###autoload
+(defmacro unbind-key (key-name &optional keymap)
+  "Unbind the given KEY-NAME, within the KEYMAP (if specified).
+See `bind-key' for more details."
+  (let ((namevar (make-symbol "name"))
+        (kdescvar (make-symbol "kdesc")))
+    `(let* ((,namevar ,key-name)
+            (,kdescvar (cons (if (stringp ,namevar) ,namevar
+                               (key-description ,namevar))
+                             (if (symbolp ,keymap) ,keymap (quote ,keymap)))))
+       (bind-key--remove (if (vectorp ,namevar) ,namevar
+                           (read-kbd-macro ,namevar))
+                         (or (if (and ,keymap (symbolp ,keymap))
+                                 (symbol-value ,keymap) ,keymap)
+                             global-map))
+       (setq personal-keybindings
+             (cl-delete-if (lambda (k) (equal (car k) ,kdescvar))
+                           personal-keybindings))
+       nil)))
+
+(defun bind-key--remove (key keymap)
+  "Remove KEY from KEYMAP.
+
+In contrast to `define-key', this function removes the binding from the 
keymap."
+  (define-key keymap key nil)
+  ;; Split M-key in ESC key
+  (setq key (cl-mapcan (lambda (k)
+                         (if (and (integerp k) (/= (logand k ?\M-\0) 0))
+                             (list ?\e (logxor k ?\M-\0))
+                           (list k)))
+                       key))
+  ;; Delete single keys directly
+  (if (= (length key) 1)
+      (delete key keymap)
+    ;; Lookup submap and delete key from there
+    (let* ((prefix (vconcat (butlast key)))
+           (submap (lookup-key keymap prefix)))
+      (unless (keymapp submap)
+        (error "Not a keymap for %s" key))
+      (when (symbolp submap)
+        (setq submap (symbol-function submap)))
+      (delete (last key) submap)
+      ;; Delete submap if it is empty
+      (when (= 1 (length submap))
+        (bind-key--remove prefix keymap)))))
+
+;;;###autoload
+(defmacro bind-key* (key-name command &optional predicate)
+  "Similar to `bind-key', but overrides any mode-specific bindings."
+  `(bind-key ,key-name ,command override-global-map ,predicate))
+
+(defun bind-keys-form (args keymap)
+  "Bind multiple keys at once.
+
+Accepts keyword arguments:
+:map MAP               - a keymap into which the keybindings should be
+                         added
+:prefix KEY            - prefix key for these bindings
+:prefix-map MAP        - name of the prefix map that should be created
+                         for these bindings
+:prefix-docstring STR  - docstring for the prefix-map variable
+:menu-name NAME        - optional menu string for prefix map
+:repeat-docstring STR  - docstring for the repeat-map variable
+:repeat-map MAP        - name of the repeat map that should be created
+                         for these bindings. If specified, the
+                         `repeat-map' property of each command bound
+                         (within the scope of the `:repeat-map' keyword)
+                         is set to this map.
+:exit BINDINGS         - Within the scope of `:repeat-map' will bind the
+                         key in the repeat map, but will not set the
+                         `repeat-map' property of the bound command.
+:continue BINDINGS     - Within the scope of `:repeat-map' forces the
+                         same behavior as if no special keyword had
+                         been used (that is, the command is bound, and
+                         it's `repeat-map' property set)
+:filter FORM           - optional form to determine when bindings apply
+
+The rest of the arguments are conses of keybinding string and a
+function symbol (unquoted)."
+  (let (map
+        prefix-doc
+        prefix-map
+        prefix
+        repeat-map
+        repeat-doc
+        repeat-type ;; Only used internally
+        filter
+        menu-name
+        pkg)
+
+    ;; Process any initial keyword arguments
+    (let ((cont t)
+          (arg-change-func 'cddr))
+      (while (and cont args)
+        (if (cond ((and (eq :map (car args))
+                        (not prefix-map))
+                   (setq map (cadr args)))
+                  ((eq :prefix-docstring (car args))
+                   (setq prefix-doc (cadr args)))
+                  ((and (eq :prefix-map (car args))
+                        (not (memq map '(global-map
+                                         override-global-map))))
+                   (setq prefix-map (cadr args)))
+                  ((eq :repeat-docstring (car args))
+                   (setq repeat-doc (cadr args)))
+                  ((and (eq :repeat-map (car args))
+                        (not (memq map '(global-map
+                                         override-global-map))))
+                   (setq repeat-map (cadr args))
+                   (setq map repeat-map))
+                  ((eq :continue (car args))
+                   (setq repeat-type :continue
+                         arg-change-func 'cdr))
+                  ((eq :exit (car args))
+                   (setq repeat-type :exit
+                         arg-change-func 'cdr))
+                  ((eq :prefix (car args))
+                   (setq prefix (cadr args)))
+                  ((eq :filter (car args))
+                   (setq filter (cadr args)) t)
+                  ((eq :menu-name (car args))
+                   (setq menu-name (cadr args)))
+                  ((eq :package (car args))
+                   (setq pkg (cadr args))))
+            (setq args (funcall arg-change-func args))
+          (setq cont nil))))
+
+    (when (or (and prefix-map (not prefix))
+              (and prefix (not prefix-map)))
+      (error "Both :prefix-map and :prefix must be supplied"))
+
+    (when repeat-type
+      (unless repeat-map
+        (error ":continue and :exit require specifying :repeat-map")))
+
+    (when (and menu-name (not prefix))
+      (error "If :menu-name is supplied, :prefix must be too"))
+
+    (unless map (setq map keymap))
+
+    ;; Process key binding arguments
+    (let (first next)
+      (while args
+        (if (keywordp (car args))
+            (progn
+              (setq next args)
+              (setq args nil))
+          (if first
+              (nconc first (list (car args)))
+            (setq first (list (car args))))
+          (setq args (cdr args))))
+
+      (cl-flet
+          ((wrap (map bindings)
+                 (if (and map pkg (not (memq map '(global-map
+                                                   override-global-map))))
+                     `((if (boundp ',map)
+                           ,(macroexp-progn bindings)
+                         (eval-after-load
+                             ,(if (symbolp pkg) `',pkg pkg)
+                           ',(macroexp-progn bindings))))
+                   bindings)))
+
+        (append
+         (when prefix-map
+           `((defvar ,prefix-map)
+             ,@(when prefix-doc `((put ',prefix-map 'variable-documentation 
,prefix-doc)))
+             ,@(if menu-name
+                   `((define-prefix-command ',prefix-map nil ,menu-name))
+                 `((define-prefix-command ',prefix-map)))
+             ,@(if (and map (not (eq map 'global-map)))
+                   (wrap map `((bind-key ,prefix ',prefix-map ,map ,filter)))
+                 `((bind-key ,prefix ',prefix-map nil ,filter)))))
+         (when repeat-map
+           `((defvar ,repeat-map (make-sparse-keymap)
+               ,@(when repeat-doc `(,repeat-doc)))))
+         (wrap map
+               (cl-mapcan
+                (lambda (form)
+                  (let ((fun (and (cdr form) (list 'function (cdr form)))))
+                    (if prefix-map
+                        `((bind-key ,(car form) ,fun ,prefix-map ,filter))
+                      (if (and map (not (eq map 'global-map)))
+                          ;; Only needed in this branch, since when
+                          ;; repeat-map is non-nil, map is always
+                          ;; non-nil
+                          `(,@(when (and repeat-map (not (eq repeat-type 
:exit)))
+                                `((put ,fun 'repeat-map ',repeat-map)))
+                            (bind-key ,(car form) ,fun ,map ,filter))
+                        `((bind-key ,(car form) ,fun nil ,filter))))))
+                first))
+         (when next
+           (bind-keys-form `(,@(when repeat-map `(:repeat-map ,repeat-map))
+                             ,@(if pkg
+                                   (cons :package (cons pkg next))
+                                 next)) map)))))))
+
+;;;###autoload
+(defmacro bind-keys (&rest args)
+  "Bind multiple keys at once.
+
+Accepts keyword arguments:
+:map MAP               - a keymap into which the keybindings should be
+                         added
+:prefix KEY            - prefix key for these bindings
+:prefix-map MAP        - name of the prefix map that should be created
+                         for these bindings
+:prefix-docstring STR  - docstring for the prefix-map variable
+:menu-name NAME        - optional menu string for prefix map
+:repeat-docstring STR  - docstring for the repeat-map variable
+:repeat-map MAP        - name of the repeat map that should be created
+                         for these bindings. If specified, the
+                         `repeat-map' property of each command bound
+                         (within the scope of the `:repeat-map' keyword)
+                         is set to this map.
+:exit BINDINGS         - Within the scope of `:repeat-map' will bind the
+                         key in the repeat map, but will not set the
+                         `repeat-map' property of the bound command.
+:continue BINDINGS     - Within the scope of `:repeat-map' forces the
+                         same behavior as if no special keyword had
+                         been used (that is, the command is bound, and
+                         it's `repeat-map' property set)
+:filter FORM           - optional form to determine when bindings apply
+
+The rest of the arguments are conses of keybinding string and a
+function symbol (unquoted)."
+  (macroexp-progn (bind-keys-form args nil)))
+
+;;;###autoload
+(defmacro bind-keys* (&rest args)
+  "Bind multiple keys at once, in `override-global-map'.
+Accepts the same keyword arguments as `bind-keys' (which see).
+
+This binds keys in such a way that bindings are not overridden by
+other modes.  See `override-global-mode'."
+  (macroexp-progn (bind-keys-form args 'override-global-map)))
+
+(defun bind-key--get-binding-description (elem)
+  (cond
+   ((listp elem)
+    (cond
+     ((memq (car elem) '(lambda function))
+      (if (and bind-key-describe-special-forms
+               (stringp (nth 2 elem)))
+          (nth 2 elem)
+        "#<lambda>"))
+     ((eq 'closure (car elem))
+      (if (and bind-key-describe-special-forms
+               (stringp (nth 3 elem)))
+          (nth 3 elem)
+        "#<closure>"))
+     ((eq 'keymap (car elem))
+      "#<keymap>")
+     (t
+      elem)))
+   ;; must be a symbol, non-symbol keymap case covered above
+   ((and bind-key-describe-special-forms (keymapp elem))
+    (let ((doc (get elem 'variable-documentation)))
+      (if (stringp doc) doc elem)))
+   ((symbolp elem)
+    elem)
+   (t
+    "#<byte-compiled lambda>")))
+
+(defun bind-key--compare-keybindings (l r)
+  (let* ((regex bind-key-segregation-regexp)
+         (lgroup (and (string-match regex (caar l))
+                      (match-string 0 (caar l))))
+         (rgroup (and (string-match regex (caar r))
+                      (match-string 0 (caar r))))
+         (lkeymap (cdar l))
+         (rkeymap (cdar r)))
+    (cond
+     ((and (null lkeymap) rkeymap)
+      (cons t t))
+     ((and lkeymap (null rkeymap))
+      (cons nil t))
+     ((and lkeymap rkeymap
+           (not (string= (symbol-name lkeymap) (symbol-name rkeymap))))
+      (cons (string< (symbol-name lkeymap) (symbol-name rkeymap)) t))
+     ((and (null lgroup) rgroup)
+      (cons t t))
+     ((and lgroup (null rgroup))
+      (cons nil t))
+     ((and lgroup rgroup)
+      (if (string= lgroup rgroup)
+          (cons (string< (caar l) (caar r)) nil)
+        (cons (string< lgroup rgroup) t)))
+     (t
+      (cons (string< (caar l) (caar r)) nil)))))
+
+;;;###autoload
+(defun describe-personal-keybindings ()
+  "Display all the personal keybindings defined by `bind-key'."
+  (interactive)
+  (with-output-to-temp-buffer "*Personal Keybindings*"
+    (princ (format (concat "Key name%s Command%s Comments\n%s %s "
+                           "---------------------\n")
+                   (make-string (- (car bind-key-column-widths) 9) ? )
+                   (make-string (- (cdr bind-key-column-widths) 8) ? )
+                   (make-string (1- (car bind-key-column-widths)) ?-)
+                   (make-string (1- (cdr bind-key-column-widths)) ?-)))
+    (let (last-binding)
+      (dolist (binding
+               (setq personal-keybindings
+                     (sort personal-keybindings
+                           (lambda (l r)
+                             (car (bind-key--compare-keybindings l r))))))
+
+        (if (not (eq (cdar last-binding) (cdar binding)))
+            (princ (format "\n\n%s: %s\n%s\n\n"
+                           (cdar binding) (caar binding)
+                           (make-string (+ 21 (car bind-key-column-widths)
+                                           (cdr bind-key-column-widths)) ?-)))
+          (if (and last-binding
+                   (cdr (bind-key--compare-keybindings last-binding binding)))
+              (princ "\n")))
+
+        (let* ((key-name (caar binding))
+               (at-present (lookup-key (or (symbol-value (cdar binding))
+                                           (current-global-map))
+                                       (read-kbd-macro key-name)))
+               (command (nth 1 binding))
+               (was-command (nth 2 binding))
+               (command-desc (bind-key--get-binding-description command))
+               (was-command-desc (and was-command
+                                      (bind-key--get-binding-description 
was-command)))
+               (at-present-desc (bind-key--get-binding-description 
at-present)))
+          (let ((line
+                 (format
+                  (format "%%-%ds%%-%ds%%s\n" (car bind-key-column-widths)
+                          (cdr bind-key-column-widths))
+                  key-name (format "`%s'" command-desc)
+                  (if (string= command-desc at-present-desc)
+                      (if (or (null was-command)
+                              (string= command-desc was-command-desc))
+                          ""
+                        (format "was `%s'" was-command-desc))
+                    (format "[now: `%s']" at-present)))))
+            (princ (if (string-match "[ \t]+\n" line)
+                       (replace-match "\n" t t line)
+                     line))))
+
+        (setq last-binding binding)))))
+
+(define-obsolete-function-alias 'get-binding-description
+  'bind-key--get-binding-description "30.1")
+(define-obsolete-function-alias 'compare-keybindings
+  'bind-key--compare-keybindings "30.1")
+
+(provide 'bind-key)
+
+;; Local Variables:
+;; outline-regexp: ";;;\\(;* [^\s\t\n]\\|###autoload\\)\\|("
+;; End:
+
+;;; bind-key.el ends here
diff --git a/lisp/use-package/use-package-bind-key.el 
b/lisp/use-package/use-package-bind-key.el
new file mode 100644
index 0000000000..4ebf54825c
--- /dev/null
+++ b/lisp/use-package/use-package-bind-key.el
@@ -0,0 +1,176 @@
+;;; use-package-bind-key.el --- Support for the :bind/:bind-keymap keywords  
-*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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:
+
+;; Provides support for the :bind, :bind*, :bind-keymap and :bind-keymap*
+;; keywords.  Note that these are currently still baked into
+;; `use-package-keywords' and `use-package-deferring-keywords', although this
+;; is harmless if they are never used.
+;;
+;; These keywords are made available by default by requiring `use-package'.
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'use-package-core)
+(require 'bind-key)
+
+;;;###autoload
+(defun use-package-autoload-keymap (keymap-symbol package override)
+  "Load PACKAGE and bind key sequence invoking this function to KEYMAP-SYMBOL.
+Then simulate pressing the same key sequence a again, so that the
+next key pressed is routed to the newly loaded keymap.
+
+This function supports use-package's :bind-keymap keyword.  It
+works by binding the given key sequence to an invocation of this
+function for a particular keymap.  The keymap is expected to be
+defined by the package.  In this way, loading the package is
+deferred until the prefix key sequence is pressed."
+  (if (not (require package nil t))
+      (use-package-error (format "Cannot load package.el: %s" package))
+    (if (and (boundp keymap-symbol)
+             (keymapp (symbol-value keymap-symbol)))
+        (let* ((kv (this-command-keys-vector))
+               (key (key-description kv))
+               (keymap (symbol-value keymap-symbol)))
+          (if override
+              (bind-key* key keymap)
+            (bind-key key keymap))
+          (setq unread-command-events
+                (mapcar (lambda (ev) (cons t ev))
+                        (listify-key-sequence kv))))
+      (use-package-error
+       (format "package.el %s failed to define keymap %s"
+               package keymap-symbol)))))
+
+;;;###autoload
+(defun use-package-normalize-binder (name keyword args)
+  (let ((arg args)
+        args*)
+    (while arg
+      (let ((x (car arg)))
+        (cond
+         ;; (KEY . COMMAND)
+         ((and (consp x)
+               (or (stringp (car x))
+                   (vectorp (car x)))
+               (or (use-package-recognize-function (cdr x) t #'stringp)))
+          (setq args* (nconc args* (list x)))
+          (setq arg (cdr arg)))
+         ;; KEYWORD
+         ;;   :map KEYMAP
+         ;;   :prefix-docstring STRING
+         ;;   :prefix-map SYMBOL
+         ;;   :prefix STRING
+        ;;   :repeat-docstring STRING
+         ;;   :repeat-map SYMBOL
+         ;;   :filter SEXP
+         ;;   :menu-name STRING
+         ;;   :package SYMBOL
+        ;;   :continue and :exit are used within :repeat-map
+         ((or (and (eq x :map) (symbolp (cadr arg)))
+              (and (eq x :prefix) (stringp (cadr arg)))
+              (and (eq x :prefix-map) (symbolp (cadr arg)))
+              (and (eq x :prefix-docstring) (stringp (cadr arg)))
+             (and (eq x :repeat-map) (symbolp (cadr arg)))
+             (eq x :continue)
+             (eq x :exit)
+              (and (eq x :repeat-docstring) (stringp (cadr arg)))
+              (eq x :filter)
+              (and (eq x :menu-name) (stringp (cadr arg)))
+              (and (eq x :package) (symbolp (cadr arg))))
+          (setq args* (nconc args* (list x (cadr arg))))
+          (setq arg (cddr arg)))
+         ((listp x)
+          (setq args*
+                (nconc args* (use-package-normalize-binder name keyword x)))
+          (setq arg (cdr arg)))
+         (t
+          ;; Error!
+          (use-package-error
+           (concat (symbol-name name)
+                   " wants arguments acceptable to the `bind-keys' macro,"
+                   " or a list of such values"))))))
+    args*))
+
+;;;; :bind, :bind*
+
+;;;###autoload
+(defalias 'use-package-normalize/:bind 'use-package-normalize-binder)
+;;;###autoload
+(defalias 'use-package-normalize/:bind* 'use-package-normalize-binder)
+
+;; jww (2017-12-07): This is too simplistic. It will fail to determine
+;; autoloads in this situation:
+;;   (use-package foo
+;;     :bind (:map foo-map (("C-a" . func))))
+;;;###autoload
+(defalias 'use-package-autoloads/:bind 'use-package-autoloads-mode)
+;;;###autoload
+(defalias 'use-package-autoloads/:bind* 'use-package-autoloads-mode)
+
+;;;###autoload
+(defun use-package-handler/:bind
+    (name _keyword args rest state &optional bind-macro)
+  (use-package-concat
+   (use-package-process-keywords name rest state)
+   `(,@(mapcar
+        #'(lambda (xs)
+            `(,(if bind-macro bind-macro 'bind-keys)
+              :package ,name ,@(use-package-normalize-commands xs)))
+        (use-package-split-list-at-keys :break args)))))
+
+(defun use-package-handler/:bind* (name keyword arg rest state)
+  (use-package-handler/:bind name keyword arg rest state 'bind-keys*))
+
+;;;; :bind-keymap, :bind-keymap*
+
+;;;###autoload
+(defalias 'use-package-normalize/:bind-keymap 'use-package-normalize-binder)
+;;;###autoload
+(defalias 'use-package-normalize/:bind-keymap* 'use-package-normalize-binder)
+
+;;;###autoload
+(defun use-package-handler/:bind-keymap
+    (name _keyword args rest state &optional override)
+  (use-package-concat
+   (use-package-process-keywords name rest state)
+   (mapcar
+    #'(lambda (binding)
+        `(,(if override 'bind-key* 'bind-key)
+          ,(car binding)
+          #'(lambda ()
+              (interactive)
+              (use-package-autoload-keymap
+               ',(cdr binding) ',(use-package-as-symbol name)
+               ,override))))
+    args)))
+
+;;;###autoload
+(defun use-package-handler/:bind-keymap* (name keyword arg rest state)
+  (use-package-handler/:bind-keymap name keyword arg rest state t))
+
+(provide 'use-package-bind-key)
+
+;;; use-package-bind-key.el ends here
diff --git a/lisp/use-package/use-package-core.el 
b/lisp/use-package/use-package-core.el
new file mode 100644
index 0000000000..1dee08e55b
--- /dev/null
+++ b/lisp/use-package/use-package-core.el
@@ -0,0 +1,1691 @@
+;;; use-package-core.el --- A configuration macro for simplifying your .emacs  
-*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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 contains the core implementation of the `use-package'
+;; macro.
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'bytecomp)
+(require 'cl-lib)
+(require 'tabulated-list)
+
+(eval-and-compile
+  ;; Declare a synthetic theme for :custom variables.
+  ;; Necessary in order to avoid having those variables saved by custom.el.
+  (deftheme use-package))
+
+(enable-theme 'use-package)
+;; Remove the synthetic use-package theme from the enabled themes, so
+;; iterating over them to "disable all themes" won't disable it.
+(setq custom-enabled-themes (remq 'use-package custom-enabled-themes))
+
+(eval-when-compile
+  (if (and (eq emacs-major-version 24) (eq emacs-minor-version 3))
+      (progn
+        (defsubst hash-table-keys (hash-table)
+          "Return a list of keys in HASH-TABLE."
+          (cl-loop for k being the hash-keys of hash-table collect k))
+        (defsubst string-suffix-p (suffix string  &optional ignore-case)
+          (let ((start-pos (- (length string) (length suffix))))
+            (and (>= start-pos 0)
+                 (eq t (compare-strings suffix nil nil
+                                        string start-pos nil ignore-case))))))
+    (require 'subr-x)))
+
+(eval-when-compile
+  (require 'regexp-opt))
+
+(defgroup use-package nil
+  "A `use-package' declaration for simplifying your `.emacs'."
+  :group 'initialization
+  :link '(custom-manual "(use-package) Top")
+  :version "29.1")
+
+(defconst use-package-version "2.4.4"
+  "This version of `use-package'.")
+
+(defcustom use-package-keywords
+  '(:disabled
+    :load-path
+    :requires
+    :defines
+    :functions
+    :preface
+    :if :when :unless
+    :no-require
+    :catch
+    :after
+    :custom
+    :custom-face
+    :bind
+    :bind*
+    :bind-keymap
+    :bind-keymap*
+    :interpreter
+    :mode
+    :magic
+    :magic-fallback
+    :hook
+    ;; Any other keyword that also declares commands to be autoloaded (such as
+    ;; :bind) must appear before this keyword.
+    :commands
+    :autoload
+    :init
+    :defer
+    :demand
+    :load
+    ;; This must occur almost last; the only forms which should appear after
+    ;; are those that must happen directly after the config forms.
+    :config)
+  "The set of valid keywords, in the order they are processed in.
+The order of this list is *very important*, so it is only
+advisable to insert new keywords, never to delete or reorder
+them.  Further, attention should be paid to the NEWS.md if the
+default order ever changes, as they may have subtle effects on
+the semantics of `use-package' declarations and may necessitate
+changing where you had inserted a new keyword earlier.
+
+Note that `:disabled' is special in this list, as it causes
+nothing at all to happen, even if the rest of the `use-package'
+declaration is incorrect."
+  :type '(repeat symbol)
+  :group 'use-package)
+
+(defcustom use-package-deferring-keywords
+  '(:bind-keymap
+    :bind-keymap*
+    :commands
+    :autoload)
+  "Unless `:demand' is used, keywords in this list imply deferred loading.
+The reason keywords like `:hook' are not in this list is that
+they only imply deferred loading if they reference actual
+function symbols that can be autoloaded from the module; whereas
+the default keywords provided here always defer loading unless
+otherwise requested."
+  :type '(repeat symbol)
+  :group 'use-package)
+
+(defcustom use-package-ignore-unknown-keywords nil
+  "If non-nil, warn instead of signaling error for unknown keywords.
+The unknown keyword and its associated arguments will be ignored
+in the `use-package' expansion."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-use-theme t
+  "If non-nil, use a custom theme to avoid saving :custom
+variables twice (once in the Custom file, once in the use-package
+call)."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-verbose nil
+  "Whether to report about loading and configuration details.
+If you customize this, then you should require the `use-package'
+feature in files that use `use-package', even if these files only
+contain compiled expansions of the macros.  If you don't do so,
+then the expanded macros do their job silently."
+  :type '(choice (const :tag "Quiet, without catching errors" errors)
+                 (const :tag "Quiet" nil)
+                 (const :tag "Verbose" t)
+                 (const :tag "Debug" debug))
+  :group 'use-package)
+
+(defcustom use-package-check-before-init nil
+  "If non-nil, check that package exists before executing its `:init' block.
+This check is performed by calling `locate-library'."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-always-defer nil
+  "If non-nil, assume `:defer t' unless `:demand' is used.
+See also `use-package-defaults', which uses this value."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-always-demand nil
+  "If non-nil, assume `:demand t' unless `:defer' is used.
+See also `use-package-defaults', which uses this value."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-defaults
+  '(;; this '(t) has special meaning; see `use-package-handler/:config'
+    (:config '(t) t)
+    (:init nil t)
+    (:catch t (lambda (name args)
+                (not use-package-expand-minimally)))
+    (:defer use-package-always-defer
+            (lambda (name args)
+              (and use-package-always-defer
+                   (not (plist-member args :defer))
+                   (not (plist-member args :demand)))))
+    (:demand use-package-always-demand
+             (lambda (name args)
+               (and use-package-always-demand
+                    (not (plist-member args :defer))
+                    (not (plist-member args :demand))))))
+  "Default values for specified `use-package' keywords.
+Each entry in the alist is a list of three elements:
+The first element is the `use-package' keyword.
+
+The second is a form that can be evaluated to get the default
+value.  It can also be a function that will receive the name of
+the `use-package' declaration and the keyword plist given to
+`use-package', in normalized form.  The value it returns should
+also be in normalized form (which is sometimes *not* what one
+would normally write in a `use-package' declaration, so use
+caution).
+
+The third element is a form that can be evaluated to determine
+whether or not to assign a default value; if it evaluates to nil,
+then the default value is not assigned even if the keyword is not
+present in the `use-package' form.  This third element may also be
+a function, in which case it receives the name of the package (as
+a symbol) and a list of keywords (in normalized form).  It should
+return nil or non-nil depending on whether defaulting should be
+attempted."
+  :type `(repeat
+          (list (symbol :tag "Keyword")
+                (choice :tag "Default value" sexp function)
+                (choice :tag "Enable if non-nil" sexp function)))
+  :group 'use-package)
+
+(defcustom use-package-merge-key-alist
+  '((:if    . (lambda (new old) `(and ,new ,old)))
+    (:after . (lambda (new old) `(:all ,new ,old)))
+    (:defer . (lambda (new old) old))
+    (:bind  . (lambda (new old) (append new (list :break) old))))
+  "Alist of keys and the functions used to merge multiple values.
+For example, if the following form is provided:
+
+  (use-package foo :if pred1 :if pred2)
+
+Then based on the above defaults, the merged result will be:
+
+  (use-package foo :if (and pred1 pred2))
+
+This is done so that, at the stage of invoking handlers, each
+handler is called only once."
+  :type `(repeat
+          (cons (choice :tag "Keyword"
+                        ,@(mapcar #'(lambda (k) (list 'const k))
+                                  use-package-keywords)
+                        (const :tag "Any" t))
+                function))
+  :group 'use-package)
+
+(defcustom use-package-hook-name-suffix "-hook"
+  "Text append to the name of hooks mentioned by :hook.
+Set to nil if you don't want this to happen; it's only a
+convenience."
+  :type '(choice string (const :tag "No suffix" nil))
+  :group 'use-package)
+
+(defcustom use-package-minimum-reported-time 0.1
+  "Minimal load time that will be reported.
+Note that `use-package-verbose' has to be set to a non-nil value
+for anything to be reported at all."
+  :type 'number
+  :group 'use-package)
+
+(defcustom use-package-inject-hooks nil
+  "If non-nil, add hooks to the `:init' and `:config' sections.
+In particular, for a given package `foo', the following hooks
+become available:
+
+  `use-package--foo--pre-init-hook'
+  `use-package--foo--post-init-hook'
+  `use-package--foo--pre-config-hook'
+  `use-package--foo--post-config-hook'
+
+This way, you can add to these hooks before evaluation of a
+`use-package` declaration, and exercise some control over what
+happens.
+
+NOTE: These hooks are run even if the user does not specify an
+`:init' or `:config' block, and they will happen at the regular
+time when initialization and configuration would have been
+performed.
+
+NOTE: If the `pre-init' hook return a nil value, that block's
+user-supplied configuration is not evaluated, so be certain to
+return t if you only wish to add behavior to what the user had
+specified."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-expand-minimally nil
+  "If non-nil, make the expanded code as minimal as possible.
+This disables:
+
+  - Printing to the *Messages* buffer of slowly-evaluating forms
+  - Capturing of load errors (normally redisplayed as warnings)
+  - Conditional loading of packages (load failures become errors)
+
+The main advantage to this variable is that, if you know your
+configuration works, it will make the byte-compiled file as
+minimal as possible.  It can also help with reading macro-expanded
+definitions, to understand the main intent of what's happening."
+  :type 'boolean
+  :group 'use-package)
+
+(defcustom use-package-form-regexp-eval
+  `(concat ,(eval-when-compile
+              (concat "^\\s-*("
+                      (regexp-opt '("use-package" "require") t)
+                      "\\s-+\\("))
+           (or (bound-and-true-p lisp-mode-symbol-regexp)
+               "\\(?:\\sw\\|\\s_\\|\\\\.\\)+") "\\)")
+  "Sexp providing regexp for finding `use-package' forms in user files.
+This is used by `use-package-jump-to-package-form' and
+`use-package-enable-imenu-support'."
+  :type 'sexp
+  :group 'use-package)
+
+(defcustom use-package-enable-imenu-support nil
+  "If non-nil, cause imenu to see `use-package' declarations.
+This is done by adjusting `lisp-imenu-generic-expression' to
+include support for finding `use-package' and `require' forms.
+
+Must be set before loading `use-package'."
+  :type 'boolean
+  :set
+  #'(lambda (sym value)
+      (eval-after-load 'lisp-mode
+        (if value
+            `(add-to-list 'lisp-imenu-generic-expression
+                          (list "Packages" ,use-package-form-regexp-eval 2))
+          `(setq lisp-imenu-generic-expression
+                 (remove (list "Packages" ,use-package-form-regexp-eval 2)
+                         lisp-imenu-generic-expression))))
+      (set-default sym value))
+  :group 'use-package)
+
+(defconst use-package-font-lock-keywords
+  '(("(\\(use-package\\)\\_>[ \t']*\\(\\(?:\\sw\\|\\s_\\)+\\)?"
+     (1 font-lock-keyword-face)
+     (2 font-lock-constant-face nil t))))
+
+(font-lock-add-keywords 'emacs-lisp-mode use-package-font-lock-keywords)
+
+(defcustom use-package-compute-statistics nil
+  "If non-nil, compute statistics concerned `use-package' declarations.
+View the statistical report using `use-package-report'.  Note that
+if this option is enabled, you must require `use-package' in your
+user init file at loadup time, or you will see errors concerning
+undefined variables."
+  :type 'boolean
+  :group 'use-package)
+
+(defvar use-package-statistics (make-hash-table))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Utility functions
+;;
+
+(defsubst use-package-error (msg)
+  "Report MSG as an error, so the user knows it came from this package."
+  (error "use-package: %s" msg))
+
+(defsubst use-package-concat (&rest elems)
+  "Delete all empty lists from ELEMS (nil or (list nil)), and append them."
+  (apply #'append (delete nil (delete (list nil) elems))))
+
+(defsubst use-package-non-nil-symbolp (sym)
+  (and sym (symbolp sym)))
+
+(defsubst use-package-as-symbol (string-or-symbol)
+  "If STRING-OR-SYMBOL is already a symbol, return it.
+Otherwise convert it to a symbol and return that."
+  (if (symbolp string-or-symbol) string-or-symbol
+    (intern string-or-symbol)))
+
+(defsubst use-package-as-string (string-or-symbol)
+  "If STRING-OR-SYMBOL is already a string, return it.
+Otherwise convert it to a string and return that."
+  (if (stringp string-or-symbol) string-or-symbol
+    (symbol-name string-or-symbol)))
+
+(defsubst use-package-regex-p (re)
+  "Return t if RE is some regexp-like thing."
+  (or (and (listp re) (eq (car re) 'rx))
+      (stringp re)))
+
+(defun use-package-normalize-regex (re)
+  "Given some regexp-like thing in RE, resolve to a regular expression."
+  (cond
+   ((and (listp re) (eq (car re) 'rx)) (eval re))
+   ((stringp re) re)
+   (t (error "Not recognized as regular expression: %s" re))))
+
+(defsubst use-package-is-pair (x car-pred cdr-pred)
+  "Return non-nil if X is a cons satisfying the given predicates.
+CAR-PRED and CDR-PRED are applied to X's `car' and `cdr',
+respectively."
+  (and (consp x)
+       (funcall car-pred (car x))
+       (funcall cdr-pred (cdr x))))
+
+(defun use-package-as-mode (string-or-symbol)
+  "If STRING-OR-SYMBOL ends in `-mode' (or its name does), return
+it as a symbol.  Otherwise, return it as a symbol with `-mode'
+appended."
+  (let ((string (use-package-as-string string-or-symbol)))
+    (intern (if (string-match "-mode\\'" string)
+                string
+              (concat string "-mode")))))
+
+(defsubst use-package-load-name (name &optional noerror)
+  "Return a form which will load or require NAME.
+It does the right thing no matter if NAME is a string or symbol.
+Argument NOERROR means to indicate load failures as a warning."
+  (if (stringp name)
+      `(load ,name ,noerror)
+    `(require ',name nil ,noerror)))
+
+(defun use-package-hook-injector (name-string keyword body)
+  "Wrap pre/post hook injections around the given BODY for KEYWORD.
+The BODY is a list of forms, so `((foo))' if only `foo' is being called."
+  (if (not use-package-inject-hooks)
+      body
+    (let ((keyword-name (substring (format "%s" keyword) 1)))
+      `((when (run-hook-with-args-until-failure
+               ',(intern (concat "use-package--" name-string
+                                 "--pre-" keyword-name "-hook")))
+          ,@body
+          (run-hooks
+           ',(intern (concat "use-package--" name-string
+                             "--post-" keyword-name "-hook"))))))))
+
+(defun use-package-with-elapsed-timer (text body)
+  "BODY is a list of forms, so `((foo))' if only `foo' is being called."
+  (declare (indent 1))
+  (if use-package-expand-minimally
+      body
+    (let ((nowvar (make-symbol "now")))
+      (if (bound-and-true-p use-package-verbose)
+          `((let ((,nowvar (current-time)))
+              (message "%s..." ,text)
+              (prog1
+                  ,(macroexp-progn body)
+                (let ((elapsed
+                       (float-time (time-subtract (current-time) ,nowvar))))
+                  (if (> elapsed ,use-package-minimum-reported-time)
+                      (message "%s...done (%.3fs)" ,text elapsed)
+                    (message "%s...done" ,text))))))
+        body))))
+
+(put 'use-package-with-elapsed-timer 'lisp-indent-function 1)
+
+(defun use-package-require (name &optional no-require body)
+  (if use-package-expand-minimally
+      (use-package-concat
+       (unless no-require
+         (list (use-package-load-name name)))
+       body)
+    (if no-require
+        body
+      (use-package-with-elapsed-timer
+          (format "Loading package %s" name)
+        `((if (not ,(use-package-load-name name t))
+              (display-warning 'use-package
+                               (format "Cannot load %s" ',name)
+                               :error)
+            ,@body))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Property lists
+;;
+
+(defun use-package-plist-delete (plist property)
+  "Delete PROPERTY from PLIST.
+This is in contrast to merely setting it to 0."
+  (let (p)
+    (while plist
+      (if (not (eq property (car plist)))
+          (setq p (plist-put p (car plist) (nth 1 plist))))
+      (setq plist (cddr plist)))
+    p))
+
+(defun use-package-plist-delete-first (plist property)
+  "Delete PROPERTY from PLIST.
+This is in contrast to merely setting it to 0."
+  (let (p)
+    (while plist
+      (if (eq property (car plist))
+          (setq p (nconc p (cddr plist))
+                plist nil)
+        (setq p (nconc p (list (car plist) (cadr plist)))
+              plist (cddr plist))))
+    p))
+
+(defsubst use-package-plist-maybe-put (plist property value)
+  "Add a VALUE for PROPERTY to PLIST, if it does not already exist."
+  (if (plist-member plist property)
+      plist
+    (plist-put plist property value)))
+
+(defsubst use-package-plist-cons (plist property value)
+  "Cons VALUE onto the head of the list at PROPERTY in PLIST."
+  (plist-put plist property (cons value (plist-get plist property))))
+
+(defsubst use-package-plist-append (plist property value)
+  "Append VALUE onto the front of the list at PROPERTY in PLIST."
+  (plist-put plist property (append value (plist-get plist property))))
+
+(defun use-package-split-list (pred xs)
+  (let ((ys (list nil)) (zs (list nil)) flip)
+    (cl-dolist (x xs)
+      (if flip
+          (nconc zs (list x))
+        (if (funcall pred x)
+            (progn
+              (setq flip t)
+              (nconc zs (list x)))
+          (nconc ys (list x)))))
+    (cons (cdr ys) (cdr zs))))
+
+(defun use-package-split-list-at-keys (key lst)
+  (and lst
+       (let ((xs (use-package-split-list (apply-partially #'eq key) lst)))
+         (cons (car xs) (use-package-split-list-at-keys key (cddr xs))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Keywords
+;;
+
+(defun use-package-keyword-index (keyword)
+  (cl-loop named outer
+           with index = 0
+           for k in use-package-keywords do
+           (if (eq k keyword)
+               (cl-return-from outer index))
+           (cl-incf index)))
+
+(defun use-package-normalize-plist (name input &optional plist merge-function)
+  "Given a pseudo-plist, normalize it to a regular plist.
+The normalized key/value pairs from input are added to PLIST,
+extending any keys already present."
+  (if (null input)
+      plist
+    (let* ((keyword (car input))
+           (xs (use-package-split-list #'keywordp (cdr input)))
+           (args (car xs))
+           (tail (cdr xs))
+           (normalizer
+            (intern-soft (concat "use-package-normalize/"
+                                 (symbol-name keyword))))
+           (arg (and (functionp normalizer)
+                     (funcall normalizer name keyword args)))
+           (error-string (format "Unrecognized keyword: %s" keyword)))
+      (if (memq keyword use-package-keywords)
+          (progn
+            (setq plist (use-package-normalize-plist
+                         name tail plist merge-function))
+            (plist-put plist keyword
+                       (if (plist-member plist keyword)
+                           (funcall merge-function keyword arg
+                                    (plist-get plist keyword))
+                         arg)))
+        (if use-package-ignore-unknown-keywords
+            (progn
+              (display-warning 'use-package error-string)
+              (use-package-normalize-plist
+               name tail plist merge-function))
+          (use-package-error error-string))))))
+
+(defun use-package-unalias-keywords (_name args)
+  (setq args (cl-nsubstitute :if :when args))
+  (let (temp)
+    (while (setq temp (plist-get args :unless))
+      (setq args (use-package-plist-delete-first args :unless)
+            args (append args `(:if (not ,temp))))))
+  args)
+
+(defun use-package-merge-keys (key new old)
+  (let ((merger (assq key use-package-merge-key-alist)))
+    (if merger
+        (funcall (cdr merger) new old)
+      (append new old))))
+
+(defun use-package-sort-keywords (plist)
+  (let (plist-grouped)
+    (while plist
+      (push (cons (car plist) (cadr plist))
+            plist-grouped)
+      (setq plist (cddr plist)))
+    (let (result)
+      (cl-dolist
+          (x
+           (nreverse
+            (sort plist-grouped
+                  #'(lambda (l r) (< (use-package-keyword-index (car l))
+                                (use-package-keyword-index (car r)))))))
+        (setq result (cons (car x) (cons (cdr x) result))))
+      result)))
+
+(defun use-package-normalize-keywords (name args)
+  (let* ((name-symbol (if (stringp name) (intern name) name))
+         (name-string (symbol-name name-symbol)))
+
+    ;; The function `elisp--local-variables' inserts this unbound variable into
+    ;; macro forms to determine the locally bound variables for
+    ;; `elisp-completion-at-point'. It ends up throwing a lot of errors since 
it
+    ;; can occupy the position of a keyword (or look like a second argument to 
a
+    ;; keyword that takes one). Deleting it when it's at the top level should 
be
+    ;; harmless since there should be no locally bound variables to discover
+    ;; here anyway.
+    (setq args (delq 'elisp--witness--lisp args))
+
+    ;; Reduce the set of keywords down to its most fundamental expression.
+    (setq args (use-package-unalias-keywords name-symbol args))
+
+    ;; Normalize keyword values, coalescing multiple occurrences.
+    (setq args (use-package-normalize-plist name-symbol args nil
+                                            #'use-package-merge-keys))
+
+    ;; Add default values for keywords not specified, when applicable.
+    (cl-dolist (spec use-package-defaults)
+      (when (let ((func (nth 2 spec)))
+              (if (and func (functionp func))
+                  (funcall func name args)
+                (eval func)))
+        (setq args (use-package-plist-maybe-put
+                    args (nth 0 spec)
+                    (let ((func (nth 1 spec)))
+                      (if (and func (functionp func))
+                          (funcall func name args)
+                        (eval func)))))))
+
+    ;; Determine any autoloads implied by the keywords used.
+    (let ((iargs args)
+          commands)
+      (while iargs
+        (when (keywordp (car iargs))
+          (let ((autoloads
+                 (intern-soft (concat "use-package-autoloads/"
+                                      (symbol-name (car iargs))))))
+            (when (functionp autoloads)
+              (setq commands
+                    ;; jww (2017-12-07): Right now we just ignored the type of
+                    ;; the autoload being requested, and assume they are all
+                    ;; `command'.
+                    (append (mapcar
+                             #'car
+                             (funcall autoloads name-symbol (car iargs)
+                                      (cadr iargs)))
+                            commands)))))
+        (setq iargs (cddr iargs)))
+      (when commands
+        (setq args
+              ;; Like `use-package-plist-append', but removing duplicates.
+              (plist-put args :commands
+                         (delete-dups
+                          (append commands (plist-get args :commands)))))))
+
+    ;; If byte-compiling, pre-load the package so all its symbols are in
+    ;; scope. This is done by prepending statements to the :preface.
+    (when (bound-and-true-p byte-compile-current-file)
+      (setq args
+            (use-package-plist-append
+             args :preface
+             (use-package-concat
+              (mapcar #'(lambda (var) `(defvar ,var))
+                      (plist-get args :defines))
+              (mapcar #'(lambda (fn) `(declare-function ,fn ,name-string))
+                      (plist-get args :functions))
+              `((eval-when-compile
+                  (with-demoted-errors
+                      ,(format "Cannot load %s: %%S" name-string)
+                    ,(when (eq use-package-verbose 'debug)
+                       `(message ,(format "Compiling package %s" name-string)))
+                    ,(unless (plist-get args :no-require)
+                       `(unless (featurep ',name-symbol)
+                          (load ,name-string nil t))))))))))
+
+    ;; Certain keywords imply :defer, if :demand was not specified.
+    (when (and (not (plist-member args :demand))
+               (not (plist-member args :defer))
+               (not (or (equal '(t) (plist-get args :load))
+                        (equal (list (use-package-as-string name))
+                               (mapcar #'use-package-as-string
+                                       (plist-get args :load)))))
+               (cl-some #'identity
+                        (mapcar (apply-partially #'plist-member args)
+                                use-package-deferring-keywords)))
+      (setq args (append args '(:defer t))))
+
+    ;; The :load keyword overrides :no-require
+    (when (and (plist-member args :load)
+               (plist-member args :no-require))
+      (setq args (use-package-plist-delete args :no-require)))
+
+    ;; If at this point no :load, :defer or :no-require has been seen, then
+    ;; :load the package itself.
+    (when (and (not (plist-member args :load))
+               (not (plist-member args :defer))
+               (not (plist-member args :no-require)))
+      (setq args (append args `(:load (,name)))))
+
+    ;; Sort the list of keywords based on the order of `use-package-keywords'.
+    (use-package-sort-keywords args)))
+
+(defun use-package-process-keywords (name plist &optional state)
+  "Process the next keyword in the free-form property list PLIST.
+The values in the PLIST have each been normalized by the function
+use-package-normalize/KEYWORD (minus the colon).
+
+STATE is a property list that the function may modify and/or
+query.  This is useful if a package defines multiple keywords and
+wishes them to have some kind of stateful interaction.
+
+Unless the KEYWORD being processed intends to ignore remaining
+keywords, it must call this function recursively, passing in the
+plist with its keyword and argument removed, and passing in the
+next value for the STATE."
+  (declare (indent 1))
+  (unless (null plist)
+    (let* ((keyword (car plist))
+           (arg (cadr plist))
+           (rest (cddr plist)))
+      (unless (keywordp keyword)
+        (use-package-error (format "%s is not a keyword" keyword)))
+      (let* ((handler (concat "use-package-handler/" (symbol-name keyword)))
+             (handler-sym (intern handler)))
+        (if (functionp handler-sym)
+            (funcall handler-sym name keyword arg rest state)
+          (use-package-error
+           (format "Keyword handler not defined: %s" handler)))))))
+
+(put 'use-package-process-keywords 'lisp-indent-function 'defun)
+
+(defun use-package-list-insert (elem xs &optional anchor after test)
+  "Insert ELEM into the list XS.
+If ANCHOR is also a keyword, place the new KEYWORD before that
+one.
+If AFTER is non-nil, insert KEYWORD either at the end of the
+keywords list, or after the ANCHOR if one has been provided.
+If TEST is non-nil, it is the test used to compare ELEM to list
+elements.  The default is `eq'.
+The modified list is returned.  The original list is not modified."
+  (let (result)
+    (dolist (k xs)
+      (if (funcall (or test #'eq) k anchor)
+          (if after
+              (setq result (cons k result)
+                    result (cons elem result))
+            (setq result (cons elem result)
+                  result (cons k result)))
+        (setq result (cons k result))))
+    (if anchor
+        (nreverse result)
+      (if after
+          (nreverse (cons elem result))
+        (cons elem (nreverse result))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Argument Processing
+;;
+
+(defun use-package-only-one (label args f)
+  "Call F on the first member of ARGS if it has exactly one element."
+  (declare (indent 1))
+  (cond
+   ((and (listp args) (listp (cdr args))
+         (= (length args) 1))
+    (funcall f label (car args)))
+   (t
+    (use-package-error
+     (concat label " wants exactly one argument")))))
+
+(put 'use-package-only-one 'lisp-indent-function 'defun)
+
+(defun use-package-as-one (label args f &optional allow-empty)
+  "Call F on the first element of ARGS if it has one element, or all of ARGS.
+If ALLOW-EMPTY is non-nil, it's OK for ARGS to be an empty list."
+  (declare (indent 1))
+  (if (if args
+          (and (listp args) (listp (cdr args)))
+        allow-empty)
+      (if (= (length args) 1)
+          (funcall f label (car args))
+        (funcall f label args))
+    (use-package-error
+     (concat label " wants a non-empty list"))))
+
+(put 'use-package-as-one 'lisp-indent-function 'defun)
+
+(defun use-package-memoize (f arg)
+  "Ensure the macro-expansion of F applied to ARG evaluates ARG
+no more than once."
+  (let ((loaded (cl-gentemp "use-package--loaded"))
+        (result (cl-gentemp "use-package--result"))
+        (next   (cl-gentemp "use-package--next")))
+    `((defvar ,loaded nil)
+      (defvar ,result nil)
+      (defvar ,next #'(lambda () (if ,loaded ,result
+                              (setq ,loaded t ,result ,arg))))
+      ,@(funcall f `((funcall ,next))))))
+
+(defsubst use-package-normalize-value (_label arg)
+  "Normalize the Lisp value given by ARG.
+The argument LABEL is ignored."
+  (cond ((null arg) nil)
+        ((eq t arg) t)
+        ((use-package-non-nil-symbolp arg)
+         `(symbol-value ',arg))
+        ((functionp arg)
+         `(funcall #',arg))
+        (t arg)))
+
+(defun use-package-normalize-symbols (label arg &optional recursed)
+  "Normalize a list of symbols."
+  (cond
+   ((use-package-non-nil-symbolp arg)
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (car (use-package-normalize-symbols label x t))) 
arg))
+   (t
+    (use-package-error
+     (concat label " wants a symbol, or list of symbols")))))
+
+(defun use-package-normalize-symlist (_name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    #'use-package-normalize-symbols))
+
+(defun use-package-normalize-recursive-symbols (label arg)
+  "Normalize a list of symbols."
+  (cond
+   ((use-package-non-nil-symbolp arg)
+    arg)
+   ((and (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (use-package-normalize-recursive-symbols label x))
+            arg))
+   (t
+    (use-package-error
+     (concat label " wants a symbol, or nested list of symbols")))))
+
+(defun use-package-normalize-recursive-symlist (_name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    #'use-package-normalize-recursive-symbols))
+
+(defun use-package-normalize-paths (label arg &optional recursed)
+  "Normalize a list of filesystem paths."
+  (cond
+   ((and arg (or (use-package-non-nil-symbolp arg) (functionp arg)))
+    (let ((value (use-package-normalize-value label arg)))
+      (use-package-normalize-paths label (eval value))))
+   ((stringp arg)
+    (let ((path (if (file-name-absolute-p arg)
+                    arg
+                  (expand-file-name arg user-emacs-directory))))
+      (list path)))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x)
+                (car (use-package-normalize-paths label x t))) arg))
+   (t
+    (use-package-error
+     (concat label " wants a directory path, or list of paths")))))
+
+(defun use-package-normalize-predicate (_name keyword args)
+  (if (null args)
+      t
+    (use-package-only-one (symbol-name keyword) args
+      #'use-package-normalize-value)))
+
+(defun use-package-normalize-form (label args)
+  "Given a list of forms, return it wrapped in `progn'."
+  (unless (listp (car args))
+    (use-package-error (concat label " wants a sexp or list of sexps")))
+  (mapcar #'(lambda (form)
+              (if (and (consp form)
+                       (memq (car form)
+                             '(use-package bind-key bind-key*
+                                unbind-key bind-keys bind-keys*)))
+                  (macroexpand form)
+                form)) args))
+
+(defun use-package-normalize-forms (_name keyword args)
+  (use-package-normalize-form (symbol-name keyword) args))
+
+(defun use-package-normalize-pairs
+    (key-pred val-pred name label arg &optional recursed)
+  "Normalize a list of pairs.
+KEY-PRED and VAL-PRED are predicates recognizing valid keys and
+values, respectively.
+If RECURSED is non-nil, recurse into sublists."
+  (cond
+   ((funcall key-pred arg)
+    (list (cons arg (use-package-as-symbol name))))
+   ((use-package-is-pair arg key-pred val-pred)
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (let (last-item)
+      (mapcar
+       #'(lambda (x)
+           (prog1
+               (let ((ret (use-package-normalize-pairs
+                           key-pred val-pred name label x t)))
+                 (if (and (listp ret)
+                          (not (keywordp last-item)))
+                     (car ret)
+                   ret))
+             (setq last-item x))) arg)))
+   (t arg)))
+
+(defun use-package-recognize-function (v &optional binding additional-pred)
+  "A predicate that recognizes functional constructions:
+  nil
+  sym
+  \\='sym
+  (quote sym)
+  #\\='sym
+  (function sym)
+  (lambda () ...)
+  \\='(lambda () ...)
+  (quote (lambda () ...))
+  #\\='(lambda () ...)
+  (function (lambda () ...))"
+  (or (if binding
+          (symbolp v)
+        (use-package-non-nil-symbolp v))
+      (and (listp v)
+           (memq (car v) '(quote function))
+           (use-package-non-nil-symbolp (cadr v)))
+      (if binding (commandp v) (functionp v))
+      (and additional-pred
+           (funcall additional-pred v))))
+
+(defun use-package-normalize-function (v)
+  "Reduce functional constructions to one of two normal forms:
+  sym
+  #\\='(lambda () ...)"
+  (cond ((symbolp v) v)
+        ((and (listp v)
+              (memq (car v) '(quote function))
+              (use-package-non-nil-symbolp (cadr v)))
+         (cadr v))
+        ((and (consp v)
+              (eq 'lambda (car v)))
+         v)
+        ((and (listp v)
+              (memq (car v) '(quote function))
+              (eq 'lambda (car (cadr v))))
+         (cadr v))
+        (t v)))
+
+(defun use-package-normalize-commands (args)
+  "Map over ARGS of the form ((_ . F) ...), normalizing functional F's."
+  (mapcar #'(lambda (x)
+              (if (consp x)
+                  (cons (car x) (use-package-normalize-function (cdr x)))
+                x))
+          args))
+
+(defun use-package-normalize-mode (name keyword args)
+  "Normalize arguments for keywords which add regexp/mode pairs to an alist."
+  (use-package-as-one (symbol-name keyword) args
+    (apply-partially #'use-package-normalize-pairs
+                     #'use-package-regex-p
+                     #'use-package-recognize-function
+                     name)))
+
+(defun use-package-autoloads-mode (_name _keyword args)
+  (mapcar
+   #'(lambda (x) (cons (cdr x) 'command))
+   (cl-remove-if-not #'(lambda (x)
+                         (and (consp x)
+                              (use-package-non-nil-symbolp (cdr x))))
+                     args)))
+
+(defun use-package-handle-mode (name alist args rest state)
+  "Handle keywords which add regexp/mode pairs to an alist."
+  (use-package-concat
+   (use-package-process-keywords name rest state)
+   (mapcar
+    #'(lambda (thing)
+        `(add-to-list
+          ',alist
+          ',(cons (use-package-normalize-regex (car thing))
+                  (cdr thing))))
+    (use-package-normalize-commands args))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Statistics
+;;
+
+(defun use-package-reset-statistics ()
+  "Reset statistics for `use-package'.
+See also `use-package-statistics'."
+  (interactive)
+  (setq use-package-statistics (make-hash-table)))
+
+(defun use-package-statistics-status (package)
+  "Return loading configuration status of PACKAGE statistics."
+  (cond ((gethash :config package)      "Configured")
+        ((gethash :init package)        "Initialized")
+        ((gethash :preface package)     "Prefaced")
+        ((gethash :use-package package) "Declared")))
+
+(defun use-package-statistics-last-event (package)
+  "Return the date when PACKAGE's status last changed.
+The date is returned as a string."
+  (or (gethash :config package)
+      (gethash :init package)
+      (gethash :preface package)
+      (gethash :use-package package)))
+
+(defun use-package-statistics-time (package)
+  "Return the time is took for PACKAGE to load."
+  (+ (float-time (gethash :config-secs package '(0 0 0 0)))
+     (float-time (gethash :init-secs package '(0 0 0 0)))
+     (float-time (gethash :preface-secs package '(0 0 0 0)))
+     (float-time (gethash :use-package-secs package '(0 0 0 0)))))
+
+(defun use-package-statistics-convert (package)
+  "Return information about PACKAGE.
+
+The information is formatted in a way suitable for
+`use-package-statistics-mode'."
+  (let ((statistics (gethash package use-package-statistics)))
+    (list
+     package
+     (vector
+      (symbol-name package)
+      (use-package-statistics-status statistics)
+      (format-time-string
+       "%H:%M:%S.%6N"
+       (use-package-statistics-last-event statistics))
+      (format "%.2f" (use-package-statistics-time statistics))))))
+
+(defun use-package-report ()
+  "Show current statistics gathered about `use-package' declarations.
+In the table that's generated, the status field has the following
+meaning:
+  Configured        :config has been processed (the package is loaded!)
+  Initialized       :init has been processed (load status unknown)
+  Prefaced          :preface has been processed
+  Declared          the use-package declaration was seen"
+  (interactive)
+  (with-current-buffer (get-buffer-create "*use-package statistics*")
+    (setq tabulated-list-entries
+          (mapcar #'use-package-statistics-convert
+                  (hash-table-keys use-package-statistics)))
+    (use-package-statistics-mode)
+    (tabulated-list-print)
+    (display-buffer (current-buffer))))
+
+(defvar use-package-statistics-status-order
+  '(("Declared"    . 0)
+    ("Prefaced"    . 1)
+    ("Initialized" . 2)
+    ("Configured"  . 3)))
+
+(define-derived-mode use-package-statistics-mode tabulated-list-mode
+  "use-package statistics"
+  "Show current statistics gathered about `use-package' declarations."
+  (setq tabulated-list-format
+        ;; The sum of column width is 80 characters:
+        [("Package" 25 t)
+         ("Status" 13
+          (lambda (a b)
+            (< (assoc-default
+                (use-package-statistics-status
+                 (gethash (car a) use-package-statistics))
+                use-package-statistics-status-order)
+               (assoc-default
+                (use-package-statistics-status
+                 (gethash (car b) use-package-statistics))
+                use-package-statistics-status-order))))
+         ("Last Event" 23
+          (lambda (a b)
+            (< (float-time
+                (use-package-statistics-last-event
+                 (gethash (car a) use-package-statistics)))
+               (float-time
+                (use-package-statistics-last-event
+                 (gethash (car b) use-package-statistics))))))
+         ("Time" 10
+          (lambda (a b)
+            (< (use-package-statistics-time
+                (gethash (car a) use-package-statistics))
+               (use-package-statistics-time
+                (gethash (car b) use-package-statistics)))))])
+  (setq tabulated-list-sort-key '("Time" . t))
+  (tabulated-list-init-header))
+
+(defun use-package-statistics-gather (keyword name after)
+  (let* ((hash (gethash name use-package-statistics
+                        (make-hash-table)))
+         (before (and after (gethash keyword hash (current-time)))))
+    (puthash keyword (current-time) hash)
+    (when after
+      (puthash (intern (concat (symbol-name keyword) "-secs"))
+               (time-subtract (current-time) before) hash))
+    (puthash name hash use-package-statistics)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; Handlers
+;;
+
+;;;; :disabled
+
+;; Don't alias this to `ignore', as that will cause the resulting
+;; function to be interactive.
+(defun use-package-normalize/:disabled (_name _keyword _arg)
+  "Do nothing, return nil.")
+
+(defun use-package-handler/:disabled (name _keyword _arg rest state)
+  (use-package-process-keywords name rest state))
+
+;;;; :if, :when and :unless
+
+(defun use-package-normalize-test (_name keyword args)
+  (use-package-only-one (symbol-name keyword) args
+    #'use-package-normalize-value))
+
+(defalias 'use-package-normalize/:if 'use-package-normalize-test)
+
+(defun use-package-handler/:if (name _keyword pred rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    `((when ,pred ,@body))))
+
+(defalias 'use-package-normalize/:when 'use-package-normalize-test)
+
+(defalias 'use-package-handler/:when 'use-package-handler/:if)
+
+(defalias 'use-package-normalize/:unless 'use-package-normalize-test)
+
+(defun use-package-handler/:unless (name _keyword pred rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    `((unless ,pred ,@body))))
+
+;;;; :requires
+
+(defalias 'use-package-normalize/:requires 'use-package-normalize-symlist)
+
+(defun use-package-handler/:requires (name _keyword requires rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (if (null requires)
+        body
+      `((when ,(if (> (length requires) 1)
+                   `(not (member nil (mapcar #'featurep ',requires)))
+                 `(featurep ',(car requires)))
+          ,@body)))))
+
+;;;; :load-path
+
+(defun use-package-normalize/:load-path (_name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    #'use-package-normalize-paths))
+
+(defun use-package-handler/:load-path (name _keyword arg rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (use-package-concat
+     (mapcar #'(lambda (path)
+                 `(eval-and-compile (add-to-list 'load-path ,path)))
+             arg)
+     body)))
+
+;;;; :no-require
+
+(defalias 'use-package-normalize/:no-require 'use-package-normalize-predicate)
+
+(defun use-package-handler/:no-require (name _keyword _arg rest state)
+  (use-package-process-keywords name rest state))
+
+;;;; :defines
+
+(defalias 'use-package-normalize/:defines 'use-package-normalize-symlist)
+
+(defun use-package-handler/:defines (name _keyword _arg rest state)
+  (use-package-process-keywords name rest state))
+
+;;;; :functions
+
+(defalias 'use-package-normalize/:functions 'use-package-normalize-symlist)
+
+(defun use-package-handler/:functions (name _keyword _arg rest state)
+  (use-package-process-keywords name rest state))
+
+;;;; :preface
+
+(defalias 'use-package-normalize/:preface 'use-package-normalize-forms)
+
+(defun use-package-handler/:preface (name _keyword arg rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (use-package-concat
+     (when use-package-compute-statistics
+       `((use-package-statistics-gather :preface ',name nil)))
+     (when arg
+       `((eval-and-compile ,@arg)))
+     body
+     (when use-package-compute-statistics
+       `((use-package-statistics-gather :preface ',name t))))))
+
+;;;; :catch
+
+(defvar use-package--form)
+(defvar use-package--hush-function #'(lambda (_keyword body) body))
+
+(defsubst use-package-hush (context keyword body)
+  `((condition-case-unless-debug err
+        ,(macroexp-progn body)
+      (error (funcall ,context ,keyword err)))))
+
+(defun use-package-normalize/:catch (_name keyword args)
+  (if (null args)
+      t
+    (use-package-only-one (symbol-name keyword) args
+      use-package--hush-function)))
+
+(defun use-package-handler/:catch (name keyword arg rest state)
+  (let* ((context (cl-gentemp "use-package--warning")))
+    (cond
+     ((not arg)
+      (use-package-process-keywords name rest state))
+     ((eq arg t)
+      `((defvar ,context
+          #'(lambda (keyword err)
+              (let ((msg (format "%s/%s: %s" ',name keyword
+                                 (error-message-string err))))
+                ,@(when (eq use-package-verbose 'debug)
+                    `((with-current-buffer
+                          (get-buffer-create "*use-package*")
+                        (goto-char (point-max))
+                        (insert "-----\n" msg ,use-package--form)
+                        (emacs-lisp-mode))
+                      (setq msg
+                            (concat msg
+                                    " (see the *use-package* buffer)"))))
+                (display-warning 'use-package msg :error))))
+        ,@(let ((use-package--hush-function
+                 (apply-partially #'use-package-hush context)))
+            (funcall use-package--hush-function keyword
+                     (use-package-process-keywords name rest state)))))
+     ((functionp arg)
+      `((defvar ,context ,arg)
+        ,@(let ((use-package--hush-function
+                 (apply-partially #'use-package-hush context)))
+            (funcall use-package--hush-function keyword
+                     (use-package-process-keywords name rest state)))))
+     (t
+      (use-package-error "The :catch keyword expects 't' or a function")))))
+
+;;;; :interpreter
+
+(defalias 'use-package-normalize/:interpreter 'use-package-normalize-mode)
+(defalias 'use-package-autoloads/:interpreter 'use-package-autoloads-mode)
+
+(defun use-package-handler/:interpreter (name _keyword arg rest state)
+  (use-package-handle-mode name 'interpreter-mode-alist arg rest state))
+
+;;;; :mode
+
+(defalias 'use-package-normalize/:mode 'use-package-normalize-mode)
+(defalias 'use-package-autoloads/:mode 'use-package-autoloads-mode)
+
+(defun use-package-handler/:mode (name _keyword arg rest state)
+  (use-package-handle-mode name 'auto-mode-alist arg rest state))
+
+;;;; :magic
+
+(defalias 'use-package-normalize/:magic 'use-package-normalize-mode)
+(defalias 'use-package-autoloads/:magic 'use-package-autoloads-mode)
+
+(defun use-package-handler/:magic (name _keyword arg rest state)
+  (use-package-handle-mode name 'magic-mode-alist arg rest state))
+
+;;;; :magic-fallback
+
+(defalias 'use-package-normalize/:magic-fallback 'use-package-normalize-mode)
+(defalias 'use-package-autoloads/:magic-fallback 'use-package-autoloads-mode)
+
+(defun use-package-handler/:magic-fallback (name _keyword arg rest state)
+  (use-package-handle-mode name 'magic-fallback-mode-alist arg rest state))
+
+;;;; :hook
+
+(defun use-package-normalize/:hook (name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    #'(lambda (label arg)
+        (unless (or (use-package-non-nil-symbolp arg) (consp arg))
+          (use-package-error
+           (concat label " a <symbol> or (<symbol or list of symbols> . 
<symbol or function>)"
+                   " or list of these")))
+        (use-package-normalize-pairs
+         #'(lambda (k)
+             (or (use-package-non-nil-symbolp k)
+                 (and k (let ((every t))
+                          (while (and every k)
+                            (if (and (consp k)
+                                     (use-package-non-nil-symbolp (car k)))
+                                (setq k (cdr k))
+                              (setq every nil)))
+                          every))))
+         #'use-package-recognize-function
+         (if (string-suffix-p "-mode" (symbol-name name))
+             name
+           (intern (concat (symbol-name name) "-mode")))
+         label arg))))
+
+(defalias 'use-package-autoloads/:hook 'use-package-autoloads-mode)
+
+(defun use-package-handler/:hook (name _keyword args rest state)
+  "Generate use-package custom keyword code."
+  (use-package-concat
+   (use-package-process-keywords name rest state)
+   (cl-mapcan
+    #'(lambda (def)
+        (let ((syms (car def))
+              (fun (cdr def)))
+          (when fun
+            (mapcar
+             #'(lambda (sym)
+                 `(add-hook
+                   (quote ,(intern
+                            (concat (symbol-name sym)
+                                    use-package-hook-name-suffix)))
+                   (function ,fun)))
+             (use-package-hook-handler-normalize-mode-symbols syms)))))
+    (use-package-normalize-commands args))))
+
+(defun use-package-hook-handler-normalize-mode-symbols (syms)
+  "Ensure that `SYMS' turns into a list of modes."
+  (if (use-package-non-nil-symbolp syms) (list syms) syms))
+
+;;;; :commands
+
+(defalias 'use-package-normalize/:commands 'use-package-normalize-symlist)
+
+(defun use-package-handler/:commands (name _keyword arg rest state)
+  (use-package-concat
+   ;; Since we deferring load, establish any necessary autoloads, and also
+   ;; keep the byte-compiler happy.
+   (let ((name-string (use-package-as-string name)))
+     (cl-mapcan
+      #'(lambda (command)
+          (when (symbolp command)
+            (append
+             (unless (plist-get state :demand)
+               `((unless (fboundp ',command)
+                   (autoload #',command ,name-string nil t))))
+             (when (bound-and-true-p byte-compile-current-file)
+               `((eval-when-compile
+                   (declare-function ,command ,name-string)))))))
+      (delete-dups arg)))
+   (use-package-process-keywords name rest state)))
+
+;;;; :autoload
+
+(defalias 'use-package-normalize/:autoload 'use-package-normalize/:commands)
+
+(defun use-package-handler/:autoload (name _keyword arg rest state)
+  (use-package-concat
+   ;; Since we deferring load, establish any necessary autoloads, and also
+   ;; keep the byte-compiler happy.
+   (let ((name-string (use-package-as-string name)))
+     (cl-mapcan
+      #'(lambda (command)
+          (when (symbolp command)
+            (append
+             (unless (plist-get state :demand)
+               `((unless (fboundp ',command)
+                   (autoload #',command ,name-string))))
+             (when (bound-and-true-p byte-compile-current-file)
+               `((eval-when-compile
+                   (declare-function ,command ,name-string)))))))
+      (delete-dups arg)))
+   (use-package-process-keywords name rest state)))
+
+;;;; :defer
+
+(defalias 'use-package-normalize/:defer 'use-package-normalize-predicate)
+
+(defun use-package-handler/:defer (name _keyword arg rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (use-package-concat
+     ;; Load the package after a set amount of idle time, if the argument to
+     ;; `:defer' was a number.
+     (when (numberp arg)
+       `((run-with-idle-timer ,arg nil #'require
+                              ',(use-package-as-symbol name) nil t)))
+     (if (or (not arg) (null body))
+         body
+       `((eval-after-load ',name ',(macroexp-progn body)))))))
+
+;;;; :after
+
+(defun use-package-normalize/:after (name keyword args)
+  (setq args (use-package-normalize-recursive-symlist name keyword args))
+  (if (consp args)
+      args
+    (list args)))
+
+(defun use-package-after-count-uses (features*)
+  "Count the number of time the body would appear in the result."
+  (cond ((use-package-non-nil-symbolp features*)
+         1)
+        ((and (consp features*)
+              (memq (car features*) '(:or :any)))
+         (let ((num 0))
+           (cl-dolist (next (cdr features*))
+             (setq num (+ num (use-package-after-count-uses next))))
+           num))
+        ((and (consp features*)
+              (memq (car features*) '(:and :all)))
+         (apply #'max (mapcar #'use-package-after-count-uses
+                              (cdr features*))))
+        ((listp features*)
+         (use-package-after-count-uses (cons :all features*)))))
+
+(defun use-package-require-after-load (features* body)
+  "Generate `eval-after-load' statements to represents FEATURES*.
+FEATURES* is a list containing keywords `:and' and `:all', where
+no keyword implies `:all'."
+  (cond
+   ((use-package-non-nil-symbolp features*)
+    `((eval-after-load ',features* ',(macroexp-progn body))))
+   ((and (consp features*)
+         (memq (car features*) '(:or :any)))
+    (cl-mapcan #'(lambda (x) (use-package-require-after-load x body))
+               (cdr features*)))
+   ((and (consp features*)
+         (memq (car features*) '(:and :all)))
+    (cl-dolist (next (cdr features*))
+      (setq body (use-package-require-after-load next body)))
+    body)
+   ((listp features*)
+    (use-package-require-after-load (cons :all features*) body))))
+
+(defun use-package-handler/:after (name _keyword arg rest state)
+  (let ((body (use-package-process-keywords name rest state))
+        (uses (use-package-after-count-uses arg)))
+    (if (or (null uses) (null body))
+        body
+      (if (<= uses 1)
+          (use-package-require-after-load arg body)
+        (use-package-memoize
+         (apply-partially #'use-package-require-after-load arg)
+         (macroexp-progn body))))))
+
+;;;; :demand
+
+(defalias 'use-package-normalize/:demand 'use-package-normalize-predicate)
+
+(defun use-package-handler/:demand (name _keyword _arg rest state)
+  (use-package-process-keywords name rest state))
+
+;;;; :custom
+
+(defun use-package-normalize/:custom (_name keyword args)
+  "Normalize use-package custom keyword."
+  (use-package-as-one (symbol-name keyword) args
+    #'(lambda (label arg)
+        (unless (listp arg)
+          (use-package-error
+           (concat label " a (<symbol> <value> [comment])"
+                   " or list of these")))
+        (if (use-package-non-nil-symbolp (car arg))
+            (list arg)
+          arg))))
+
+(defun use-package-handler/:custom (name _keyword args rest state)
+  "Generate use-package custom keyword code."
+  (use-package-concat
+   (if (bound-and-true-p use-package-use-theme)
+       `((let ((custom--inhibit-theme-enable nil))
+           ;; Declare the theme here so use-package can be required inside
+           ;; eval-and-compile without warnings about unknown theme.
+           (unless (memq 'use-package custom-known-themes)
+             (deftheme use-package)
+             (enable-theme 'use-package)
+             (setq custom-enabled-themes (remq 'use-package 
custom-enabled-themes)))
+           (custom-theme-set-variables
+            'use-package
+            ,@(mapcar
+               #'(lambda (def)
+                   (let ((variable (nth 0 def))
+                         (value (nth 1 def))
+                         (comment (nth 2 def)))
+                     (unless (and comment (stringp comment))
+                       (setq comment (format "Customized with use-package %s" 
name)))
+                     `'(,variable ,value nil () ,comment)))
+               args))))
+     (mapcar
+      #'(lambda (def)
+          (let ((variable (nth 0 def))
+                (value (nth 1 def))
+                (comment (nth 2 def)))
+            (unless (and comment (stringp comment))
+              (setq comment (format "Customized with use-package %s" name)))
+            `(customize-set-variable (quote ,variable) ,value ,comment)))
+      args))
+   (use-package-process-keywords name rest state)))
+
+;;;; :custom-face
+
+(defun use-package-normalize/:custom-face (name-symbol _keyword arg)
+  "Normalize use-package custom-face keyword."
+  (let ((error-msg
+         (format "%s wants a (<symbol> <face-spec> [spec-type]) or list of 
these"
+                 name-symbol)))
+    (unless (listp arg)
+      (use-package-error error-msg))
+    (cl-dolist (def arg arg)
+      (unless (listp def)
+        (use-package-error error-msg))
+      (let ((face (nth 0 def))
+            (spec (nth 1 def)))
+        (when (or (not face)
+                  (not spec)
+                  (> (length def) 3))
+          (use-package-error error-msg))))))
+
+(defun use-package-handler/:custom-face (name _keyword args rest state)
+  "Generate use-package custom-face keyword code."
+  (use-package-concat
+   (mapcar #'(lambda (def) `(apply #'face-spec-set (backquote ,def))) args)
+   (use-package-process-keywords name rest state)))
+
+;;;; :init
+
+(defalias 'use-package-normalize/:init 'use-package-normalize-forms)
+
+(defun use-package-handler/:init (name _keyword arg rest state)
+  (use-package-concat
+   (when use-package-compute-statistics
+     `((use-package-statistics-gather :init ',name nil)))
+   (let ((init-body
+          (use-package-hook-injector (use-package-as-string name)
+                                     :init arg)))
+     (when init-body
+       (funcall use-package--hush-function :init
+                (if use-package-check-before-init
+                    `((when (locate-library ,(use-package-as-string name))
+                        ,@init-body))
+                  init-body))))
+   (use-package-process-keywords name rest state)
+   (when use-package-compute-statistics
+     `((use-package-statistics-gather :init ',name t)))))
+
+;;;; :load
+
+(defun use-package-normalize/:load (name keyword args)
+  (setq args (use-package-normalize-recursive-symlist name keyword args))
+  (if (consp args)
+      args
+    (list args)))
+
+(defun use-package-handler/:load (name _keyword arg rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (cl-dolist (pkg arg)
+      (setq body (use-package-require (if (eq t pkg) name pkg) nil body)))
+    body))
+
+;;;; :config
+
+(defalias 'use-package-normalize/:config 'use-package-normalize-forms)
+
+(defun use-package-handler/:config (name _keyword arg rest state)
+  (let* ((body (use-package-process-keywords name rest state))
+         (name-symbol (use-package-as-symbol name)))
+    (use-package-concat
+     (when use-package-compute-statistics
+       `((use-package-statistics-gather :config ',name nil)))
+     (if (and (or (null arg) (equal arg '(t))) (not use-package-inject-hooks))
+         body
+       (use-package-with-elapsed-timer
+           (format "Configuring package %s" name-symbol)
+         (funcall use-package--hush-function :config
+                  (use-package-concat
+                   (use-package-hook-injector
+                    (symbol-name name-symbol) :config arg)
+                   body
+                   (list t)))))
+     (when use-package-compute-statistics
+       `((use-package-statistics-gather :config ',name t))))))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;; The main macro
+;;
+
+(defmacro use-package-core (name args)
+  `(let* ((args* (use-package-normalize-keywords ,name ,args))
+          (use-package--form
+           (if (eq use-package-verbose 'debug)
+               (concat "\n\n"
+                       (pp-to-string `(use-package ,name ,@,args))
+                       "\n  -->\n\n"
+                       (pp-to-string `(use-package ,name ,@args*))
+                       "\n  ==>\n\n"
+                       (pp-to-string
+                        (macroexp-progn
+                         (let ((use-package-verbose 'errors)
+                               (use-package-expand-minimally t))
+                           (use-package-process-keywords name args*
+                             (and (plist-get args* :demand)
+                                  (list :demand t)))))))
+             "")))
+     (use-package-process-keywords name args*
+       (and (plist-get args* :demand)
+            (list :demand t)))))
+
+;;;###autoload
+(defmacro use-package (name &rest args)
+  "Declare an Emacs package by specifying a group of configuration options.
+
+For the full documentation, see Info node `(use-package) top'.
+Usage:
+
+  (use-package package-name
+     [:keyword [option]]...)
+
+:init            Code to run before PACKAGE-NAME has been loaded.
+:config          Code to run after PACKAGE-NAME has been loaded.  Note that
+                 if loading is deferred for any reason, this code does not
+                 execute until the lazy load has occurred.
+:preface         Code to be run before everything except `:disabled'; this
+                 can be used to define functions for use in `:if', or that
+                 should be seen by the byte-compiler.
+
+:mode            Form to be added to `auto-mode-alist'.
+:magic           Form to be added to `magic-mode-alist'.
+:magic-fallback  Form to be added to `magic-fallback-mode-alist'.
+:interpreter     Form to be added to `interpreter-mode-alist'.
+
+:commands        Define autoloads for commands that will be defined by the
+                 package.  This is useful if the package is being lazily
+                 loaded, and you wish to conditionally call functions in your
+                 `:init' block that are defined in the package.
+:autoload        Similar to :commands, but it for no-interactive one.
+:hook            Specify hook(s) to attach this package to.
+
+:bind            Bind keys, and define autoloads for the bound commands.
+:bind*           Bind keys, and define autoloads for the bound commands,
+                 *overriding all minor mode bindings*.
+:bind-keymap     Bind a key prefix to an auto-loaded keymap defined in the
+                 package.  This is like `:bind', but for keymaps.
+:bind-keymap*    Like `:bind-keymap', but overrides all minor mode bindings
+
+:defer           Defer loading of a package -- this is implied when using
+                 `:commands', `:bind', `:bind*', `:mode', `:magic', `:hook',
+                 `:magic-fallback', or `:interpreter'.  This can be an integer,
+                 to force loading after N seconds of idle time, if the package
+                 has not already been loaded.
+:demand          Prevent the automatic deferred loading introduced by 
constructs
+                 such as `:bind' (see `:defer' for the complete list).
+
+:after           Delay the effect of the use-package declaration
+                 until after the named libraries have loaded.
+                 Before they have been loaded, no other keyword
+                 has any effect at all, and once they have been
+                 loaded it is as if `:after' was not specified.
+
+:if EXPR         Initialize and load only if EXPR evaluates to a non-nil value.
+:disabled        The package is ignored completely if this keyword is present.
+:defines         Declare certain variables to silence the byte-compiler.
+:functions       Declare certain functions to silence the byte-compiler.
+:load-path       Add to the `load-path' before attempting to load the package.
+:diminish        Support for diminish.el (if installed).
+:delight         Support for delight.el (if installed).
+:custom          Call `Custom-set' or `set-default' with each variable
+                 definition without modifying the Emacs `custom-file'.
+                 (compare with `custom-set-variables').
+:custom-face     Call `custom-set-faces' with each face definition.
+:ensure          Loads the package using package.el if necessary.
+:pin             Pin the package to an archive."
+  (declare (indent defun))
+  (unless (memq :disabled args)
+    (macroexp-progn
+     (use-package-concat
+      (when use-package-compute-statistics
+        `((use-package-statistics-gather :use-package ',name nil)))
+      (if (eq use-package-verbose 'errors)
+          (use-package-core name args)
+        (condition-case-unless-debug err
+            (use-package-core name args)
+          (error
+           (ignore
+            (display-warning
+             'use-package
+             (format "Failed to parse package %s: %s"
+                     name (error-message-string err)) :error)))))
+      (when use-package-compute-statistics
+        `((use-package-statistics-gather :use-package ',name t)))))))
+
+(provide 'use-package-core)
+
+;;; use-package-core.el ends here
diff --git a/lisp/use-package/use-package-delight.el 
b/lisp/use-package/use-package-delight.el
new file mode 100644
index 0000000000..41978b94f4
--- /dev/null
+++ b/lisp/use-package/use-package-delight.el
@@ -0,0 +1,88 @@
+;;; use-package-delight.el --- Support for the :delight keyword  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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:
+
+;; Provides support for the :delight keyword, which is made available
+;; by default by requiring `use-package'.  Using it requires the
+;; `delight' package to be installed (available on GNU ELPA).
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'use-package-core)
+
+(defun use-package-normalize-delight (name args)
+  "Normalize ARGS for a single call to `delight'."
+  (when (eq :eval (car args))
+    ;; Handle likely common mistake.
+    (use-package-error ":delight mode line constructs must be quoted"))
+  (cond ((and (= (length args) 1)
+              (use-package-non-nil-symbolp (car args)))
+         `(,(nth 0 args) nil ,name))
+        ((= (length args) 2)
+         `(,(nth 0 args) ,(nth 1 args) ,name))
+        ((= (length args) 3)
+         args)
+        (t
+         (use-package-error
+          ":delight expects `delight' arguments or a list of them"))))
+
+;;;###autoload
+(defun use-package-normalize/:delight (name _keyword args)
+  "Normalize arguments to delight."
+  (cond ((null args)
+         `((,(use-package-as-mode name) nil ,name)))
+        ((and (= (length args) 1)
+              (use-package-non-nil-symbolp (car args)))
+         `((,(car args) nil ,name)))
+        ((and (= (length args) 1)
+              (stringp (car args)))
+         `((,(use-package-as-mode name) ,(car args) ,name)))
+        ((and (= (length args) 1)
+              (listp (car args))
+              (eq 'quote (caar args)))
+         `((,(use-package-as-mode name) ,@(cdar args) ,name)))
+        ((and (= (length args) 2)
+              (listp (nth 1 args))
+              (eq 'quote (car (nth 1 args))))
+         `((,(car args) ,@(cdr (nth 1 args)) ,name)))
+        (t (mapcar
+            (apply-partially #'use-package-normalize-delight name)
+            (if (use-package-non-nil-symbolp (car args))
+                (list args)
+              args)))))
+
+;;;###autoload
+(defun use-package-handler/:delight (name _keyword args rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (use-package-concat
+     body
+     `((if (fboundp 'delight)
+           (delight '(,@args)))))))
+
+(add-to-list 'use-package-keywords :delight t)
+
+(provide 'use-package-delight)
+
+;;; use-package-delight.el ends here
diff --git a/lisp/use-package/use-package-diminish.el 
b/lisp/use-package/use-package-diminish.el
new file mode 100644
index 0000000000..7fff93b0e9
--- /dev/null
+++ b/lisp/use-package/use-package-diminish.el
@@ -0,0 +1,77 @@
+;;; use-package-diminish.el --- Support for the :diminish keyword  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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:
+
+;; Provides support for the :diminish keyword, which is made available
+;; by default by requiring `use-package'.  Using it requires the
+;; `diminish' package to be installed (available on GNU ELPA).
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'use-package-core)
+
+(defun use-package-normalize-diminish (name label arg &optional recursed)
+  "Normalize the arguments to diminish down to a list of one of two forms:
+     SYMBOL
+     (SYMBOL . STRING)"
+  (cond
+   ((not arg)
+    (list (use-package-as-mode name)))
+   ((use-package-non-nil-symbolp arg)
+    (list arg))
+   ((stringp arg)
+    (list (cons (use-package-as-mode name) arg)))
+   ((and (consp arg) (stringp (cdr arg)))
+    (list arg))
+   ((and (not recursed) (listp arg) (listp (cdr arg)))
+    (mapcar #'(lambda (x) (car (use-package-normalize-diminish
+                           name label x t))) arg))
+   (t
+    (use-package-error
+     (concat label " wants a string, symbol, "
+             "(symbol . string) or list of these")))))
+
+;;;###autoload
+(defun use-package-normalize/:diminish (name keyword args)
+  (use-package-as-one (symbol-name keyword) args
+    (apply-partially #'use-package-normalize-diminish name) t))
+
+;;;###autoload
+(defun use-package-handler/:diminish (name _keyword arg rest state)
+  (let ((body (use-package-process-keywords name rest state)))
+    (use-package-concat
+     (mapcar #'(lambda (var)
+                 `(if (fboundp 'diminish)
+                      ,(if (consp var)
+                           `(diminish ',(car var) ,(cdr var))
+                         `(diminish ',var))))
+             arg)
+     body)))
+
+(add-to-list 'use-package-keywords :diminish t)
+
+(provide 'use-package-diminish)
+
+;;; use-package-diminish.el ends here
diff --git a/lisp/use-package/use-package-ensure-system-package.el 
b/lisp/use-package/use-package-ensure-system-package.el
new file mode 100644
index 0000000000..6681e5afb7
--- /dev/null
+++ b/lisp/use-package/use-package-ensure-system-package.el
@@ -0,0 +1,106 @@
+;;; use-package-ensure-system-package.el --- auto install system packages  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2022 Free Software Foundation, Inc.
+
+;; Author: Justin Talbott <justin@waymondo.com>
+;; Keywords: convenience, tools, extensions
+;; URL: https://github.com/waymondo/use-package-ensure-system-package
+;; Version: 0.2
+;; Package-Requires: ((use-package "2.1") (system-packages "1.0.4"))
+;; Filename: use-package-ensure-system-package.el
+
+;; 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:
+
+;; The `:ensure-system-package` keyword allows you to ensure system
+;; binaries exist alongside your `use-package` declarations.  Using it
+;; requires the `system-packages' package to be installed (available
+;; on GNU ELPA).
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'use-package)
+(require 'system-packages nil t)
+
+(eval-when-compile
+  (declare-function system-packages-get-command "system-packages"))
+
+(defvar use-package-ensure-system-package--custom-packages '()
+  "List of commands used to install custom packages.")
+
+(defun use-package-ensure-system-package-consify (arg)
+  "Turn ARG into a cons of the form (PACKAGE-NAME . INSTALL-COMMAND')."
+  (cond
+   ((stringp arg)
+    (cons arg `(system-packages-install ,arg)))
+   ((symbolp arg)
+    (cons arg `(system-packages-install ,(symbol-name arg))))
+   ((consp arg)
+    (cond
+     ((not (cdr arg))
+      (use-package-ensure-system-package-consify (car arg)))
+     ((stringp (cdr arg))
+      (progn
+       (push (cdr arg) use-package-ensure-system-package--custom-packages)
+       (cons (car arg) `(async-shell-command ,(cdr arg)))))
+     (t
+      (cons (car arg)
+           `(system-packages-install ,(symbol-name (cdr arg)))))))))
+
+(defun use-package-ensure-system-package-update-custom-packages ()
+  "Update custom packages (not installed by system package manager).
+Run the same commands used for installing them."
+  (interactive)
+  (dolist (cmd use-package-ensure-system-package--custom-packages)
+    (async-shell-command cmd)))
+
+;;;###autoload
+(defun use-package-normalize/:ensure-system-package (_name-symbol keyword args)
+  "Turn ARGS into a list of conses of the form (PACKAGE-NAME . 
INSTALL-COMMAND)."
+  (use-package-as-one (symbol-name keyword) args
+    (lambda (_label arg)
+      (cond
+       ((and (listp arg) (listp (cdr arg)))
+        (mapcar #'use-package-ensure-system-package-consify arg))
+       (t
+        (list (use-package-ensure-system-package-consify arg)))))))
+
+(defun use-package-ensure-system-package-exists? (file-or-exe)
+  "If FILE-OR-EXE is a string, ensure the file path exists.
+If it is a symbol, ensure the binary exist."
+  (if (stringp file-or-exe)
+      (file-exists-p file-or-exe)
+    (executable-find (symbol-name file-or-exe))))
+
+
+;;;###autoload
+(defun use-package-handler/:ensure-system-package (name _keyword arg rest 
state)
+  "Execute the handler for `:ensure-system-package' keyword in `use-package'."
+  (let ((body (use-package-process-keywords name rest state)))
+    (use-package-concat
+     (mapcar #'(lambda (cons)
+                 `(unless (use-package-ensure-system-package-exists? ',(car 
cons))
+                   ,(cdr cons))) arg)
+     body)))
+
+(add-to-list 'use-package-keywords :ensure-system-package t)
+
+(provide 'use-package-ensure-system-package)
+
+;;; use-package-ensure-system-package.el ends here
diff --git a/lisp/use-package/use-package-ensure.el 
b/lisp/use-package/use-package-ensure.el
new file mode 100644
index 0000000000..dae0312dba
--- /dev/null
+++ b/lisp/use-package/use-package-ensure.el
@@ -0,0 +1,212 @@
+;;; use-package-ensure.el --- Support for the :ensure and :pin keywords  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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:
+
+;; Provides support for the :ensure and :pin keywords, which are made
+;; available by default by requiring `use-package'.
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'use-package-core)
+
+(defgroup use-package-ensure nil
+  "Support for :ensure and :pin keywords in `use-package' declarations."
+  :group 'use-package
+  :link '(custom-manual "(use-package) Installing packages")
+  :version "29.1")
+
+(eval-when-compile
+  (declare-function package-installed-p "package")
+  (declare-function package-read-all-archive-contents "package" ()))
+
+(defcustom use-package-always-ensure nil
+  "Treat every package as though it had specified using `:ensure SEXP'.
+See also `use-package-defaults', which uses this value."
+  :type 'sexp
+  :group 'use-package-ensure)
+
+(defcustom use-package-always-pin nil
+  "Treat every package as though it had specified using `:pin SYM'.
+See also `use-package-defaults', which uses this value."
+  :type 'symbol
+  :group 'use-package-ensure)
+
+(defcustom use-package-ensure-function 'use-package-ensure-elpa
+  "Function that ensures a package is installed.
+This function is called with three arguments: the name of the
+package declared in the `use-package' form; the arguments passed
+to all `:ensure' keywords (always a list, even if only one); and
+the current `state' plist created by previous handlers.
+
+Note that this function is called whenever `:ensure' is provided,
+even if it is nil.  It is up to the function to decide on the
+semantics of the various values for `:ensure'.
+
+This function should return non-nil if the package is installed.
+
+The default value uses package.el to install the package."
+  :type '(choice (const :tag "package.el" use-package-ensure-elpa)
+                 (function :tag "Custom"))
+  :group 'use-package-ensure)
+
+;;;; :pin
+
+(defun use-package-normalize/:pin (_name keyword args)
+  (use-package-only-one (symbol-name keyword) args
+    #'(lambda (_label arg)
+        (cond
+         ((stringp arg) arg)
+         ((use-package-non-nil-symbolp arg) (symbol-name arg))
+         (t
+          (use-package-error
+           ":pin wants an archive name (a string)"))))))
+
+(eval-when-compile
+  (defvar package-pinned-packages)
+  (defvar package-archives))
+
+(defun use-package-archive-exists-p (archive)
+  "Check if a given ARCHIVE is enabled.
+
+ARCHIVE can be a string or a symbol or `manual' to indicate a
+manually updated package."
+  (if (member archive '(manual "manual"))
+      't
+    (let ((valid nil))
+      (dolist (pa package-archives)
+        (when (member archive (list (car pa) (intern (car pa))))
+          (setq valid 't)))
+      valid)))
+
+(defun use-package-pin-package (package archive)
+  "Pin PACKAGE to ARCHIVE."
+  (unless (boundp 'package-pinned-packages)
+    (setq package-pinned-packages ()))
+  (let ((archive-symbol (if (symbolp archive) archive (intern archive)))
+        (archive-name   (if (stringp archive) archive (symbol-name archive))))
+    (if (use-package-archive-exists-p archive-symbol)
+        (add-to-list 'package-pinned-packages (cons package archive-name))
+      (error "Archive '%s' requested for package '%s' is not available"
+             archive-name package))
+    (unless (bound-and-true-p package--initialized)
+      (package-initialize t))))
+
+(defun use-package-handler/:pin (name _keyword archive-name rest state)
+  (let ((body (use-package-process-keywords name rest state))
+        (pin-form (if archive-name
+                      `(use-package-pin-package ',(use-package-as-symbol name)
+                                                ,archive-name))))
+    ;; Pinning should occur just before ensuring
+    ;; See `use-package-handler/:ensure'.
+    (if (bound-and-true-p byte-compile-current-file)
+        (eval pin-form)              ; Eval when byte-compiling,
+      (push pin-form body))          ; or else wait until runtime.
+    body))
+
+;;;; :ensure
+
+(defvar package-archive-contents)
+
+;;;###autoload
+(defun use-package-normalize/:ensure (_name keyword args)
+  (if (null args)
+      (list t)
+    (use-package-only-one (symbol-name keyword) args
+      #'(lambda (_label arg)
+          (cond
+           ((symbolp arg)
+            (list arg))
+           ((and (listp arg) (= 3 (length arg))
+                 (symbolp (nth 0 arg))
+                 (eq :pin (nth 1 arg))
+                 (or (stringp (nth 2 arg))
+                     (symbolp (nth 2 arg))))
+            (list (cons (nth 0 arg) (nth 2 arg))))
+           (t
+            (use-package-error
+             (concat ":ensure wants an optional package name "
+                     "(an unquoted symbol name), or (<symbol> :pin 
<string>)"))))))))
+
+(defun use-package-ensure-elpa (name args _state &optional _no-refresh)
+  (dolist (ensure args)
+    (let ((package
+           (or (and (eq ensure t) (use-package-as-symbol name))
+               ensure)))
+      (when package
+        (require 'package)
+        (when (consp package)
+          (use-package-pin-package (car package) (cdr package))
+          (setq package (car package)))
+        (unless (package-installed-p package)
+          (condition-case-unless-debug err
+              (progn
+                (when (assoc package (bound-and-true-p
+                                      package-pinned-packages))
+                  (package-read-all-archive-contents))
+                (if (assoc package package-archive-contents)
+                    (package-install package)
+                  (package-refresh-contents)
+                  (when (assoc package (bound-and-true-p
+                                        package-pinned-packages))
+                    (package-read-all-archive-contents))
+                  (package-install package))
+                t)
+            (error
+             (display-warning 'use-package
+                              (format "Failed to install %s: %s"
+                                      name (error-message-string err))
+                              :error))))))))
+
+;;;###autoload
+(defun use-package-handler/:ensure (name _keyword ensure rest state)
+  (let* ((body (use-package-process-keywords name rest state)))
+    ;; We want to avoid installing packages when the `use-package' macro is
+    ;; being macro-expanded by elisp completion (see `lisp--local-variables'),
+    ;; but still install packages when byte-compiling, to avoid requiring
+    ;; `package' at runtime.
+    (if (bound-and-true-p byte-compile-current-file)
+        ;; Eval when byte-compiling,
+        (funcall use-package-ensure-function name ensure state)
+      ;;  or else wait until runtime.
+      (push `(,use-package-ensure-function ',name ',ensure ',state)
+            body))
+    body))
+
+(add-to-list 'use-package-defaults
+             '(:ensure (list use-package-always-ensure)
+                       (lambda (name args)
+                         (and use-package-always-ensure
+                              (not (plist-member args :load-path))))) t)
+
+(add-to-list 'use-package-defaults
+             '(:pin use-package-always-pin use-package-always-pin) t)
+
+(add-to-list 'use-package-keywords :ensure)
+(add-to-list 'use-package-keywords :pin)
+
+(provide 'use-package-ensure)
+
+;;; use-package-ensure.el ends here
diff --git a/lisp/use-package/use-package-jump.el 
b/lisp/use-package/use-package-jump.el
new file mode 100644
index 0000000000..6fc52afd28
--- /dev/null
+++ b/lisp/use-package/use-package-jump.el
@@ -0,0 +1,74 @@
+;;; use-package-jump.el --- Attempt to jump to a use-package declaration  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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:
+
+;; Provides the command `M-x use-package-jump-to-package-form'.  However, it
+;; only works if the package being jumped to was required during
+;; initialization.  If it was autoloaded, it will not work.
+;; Improvements are needed.
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'use-package-core)
+
+(defun use-package-find-require (package)
+  "Find file that required PACKAGE by searching `load-history'.
+Returns an absolute file path or nil if none is found."
+  (catch 'suspect
+    (dolist (filespec load-history)
+      (dolist (entry (cdr filespec))
+        (when (equal entry (cons 'require package))
+          (throw 'suspect (car filespec)))))))
+
+;;;###autoload
+(defun use-package-jump-to-package-form (package)
+  "Attempt to find and jump to the `use-package' form that loaded PACKAGE.
+This will only find the form if that form actually required
+PACKAGE.  If PACKAGE was previously required then this function
+will jump to the file that originally required PACKAGE instead."
+  (interactive (list (completing-read "Package: " features)))
+  (let* ((package (if (stringp package) (intern package) package))
+         (requiring-file (use-package-find-require package))
+         file location)
+    (if (null requiring-file)
+        (user-error "Can't find file requiring file; may have been autoloaded")
+      (setq file (if (string= (file-name-extension requiring-file) "elc")
+                     (concat (file-name-sans-extension requiring-file) ".el")
+                   requiring-file))
+      (when (file-exists-p file)
+        (find-file-other-window file)
+        (save-excursion
+          (goto-char (point-min))
+          (setq location
+                (re-search-forward
+                 (format (eval use-package-form-regexp-eval) package) nil t)))
+        (if (null location)
+            (message "No use-package form found.")
+          (goto-char location)
+          (beginning-of-line))))))
+
+(provide 'use-package-jump)
+
+;;; use-package-jump.el ends here
diff --git a/lisp/use-package/use-package-lint.el 
b/lisp/use-package/use-package-lint.el
new file mode 100644
index 0000000000..498213a76b
--- /dev/null
+++ b/lisp/use-package/use-package-lint.el
@@ -0,0 +1,80 @@
+;;; use-package-lint.el --- Attempt to find errors in use-package declarations 
 -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+
+;; 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:
+
+;; Provides the command `M-x use-package-lint'.
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'use-package-core)
+
+(defun use-package-lint-declaration (name plist)
+  (dolist (path (plist-get plist :load-path))
+    (unless (file-exists-p path)
+      (display-warning
+       'use-package
+       (format "%s :load-path does not exist: %s"
+               name path) :error)))
+
+  (unless (or (plist-member plist :disabled)
+              (plist-get plist :no-require)
+              (locate-library (use-package-as-string name) nil
+                              (plist-get plist :load-path)))
+    (display-warning
+     'use-package
+     (format "%s module cannot be located" name) :error))
+
+  ;; (dolist (command (plist-get plist :commands))
+  ;;   (unless (string= (find-lisp-object-file-name command nil)
+  ;;                    (locate-library (use-package-as-string name) nil
+  ;;                                    (plist-get plist :load-path)))
+  ;;     (display-warning
+  ;;      'use-package
+  ;;      (format "%s :command is from different path: %s"
+  ;;              name (symbol-name command)) :error)))
+  )
+
+;;;###autoload
+(defun use-package-lint ()
+  "Check for errors in `use-package' declarations.
+For example, if the module's `:if' condition is met, but even
+with the specified `:load-path' the module cannot be found."
+  (interactive)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((re (eval use-package-form-regexp-eval)))
+      (while (re-search-forward re nil t)
+        (goto-char (match-beginning 0))
+        (let ((decl (read (current-buffer))))
+          (when (eq (car decl) 'use-package)
+            (use-package-lint-declaration
+             (use-package-as-string (cadr decl))
+             (use-package-normalize-keywords
+              (cadr decl) (cddr decl)))))))))
+
+(provide 'use-package-lint)
+
+;;; use-package-lint.el ends here
diff --git a/lisp/use-package/use-package.el b/lisp/use-package/use-package.el
new file mode 100644
index 0000000000..0929696466
--- /dev/null
+++ b/lisp/use-package/use-package.el
@@ -0,0 +1,53 @@
+;;; use-package.el --- A configuration macro for simplifying your .emacs  -*- 
lexical-binding: t; -*-
+
+;; Copyright (C) 2012-2022 Free Software Foundation, Inc.
+
+;; Author: John Wiegley <johnw@newartisans.com>
+;; Maintainer: John Wiegley <johnw@newartisans.com>
+;; Created: 17 Jun 2012
+;; Version: 2.4.4
+;; Package-Requires: ((emacs "24.3") (bind-key "2.4"))
+;; Keywords: dotemacs startup speed config package extensions
+;; URL: https://github.com/jwiegley/use-package
+
+;; 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:
+
+;; The `use-package' declaration macro allows you to isolate package
+;; configuration in your init file in a way that is
+;; performance-oriented and, well, just tidy.  I created it because I
+;; have over 80 packages that I use in Emacs, and things were getting
+;; difficult to manage.  Yet with this utility my total load time is
+;; just under 1 second, with no loss of functionality!
+;;
+;; See the `use-package' info manual for more information.
+
+;;; Code:
+
+(require 'use-package-core)
+
+(require 'use-package-bind-key)
+(require 'use-package-diminish)
+(require 'use-package-delight)
+(require 'use-package-ensure)
+
+(declare-function use-package-jump-to-package-form "use-package-jump")
+(autoload #'use-package-jump-to-package-form "use-package-jump" nil t)
+
+(provide 'use-package)
+
+;;; use-package.el ends here
diff --git a/lisp/vc/vc-git.el b/lisp/vc/vc-git.el
index 59dfb6c125..9f27f759d3 100644
--- a/lisp/vc/vc-git.el
+++ b/lisp/vc/vc-git.el
@@ -1048,7 +1048,7 @@ It is based on `log-edit-mode', and has Git-specific 
extensions."
                         (string-replace file-diff "" vc-git-patch-string))
                 (user-error "Index not empty"))
               (setq pos (point))))))
-      (let ((patch-file (make-temp-file "git-patch")))
+      (let ((patch-file (make-nearby-temp-file "git-patch")))
         (with-temp-file patch-file
           (insert vc-git-patch-string))
         (unwind-protect
@@ -1434,11 +1434,11 @@ log entries."
          `((,log-view-message-re (1 'change-log-acknowledgment)))
          ;; Handle the case:
          ;; user: foo@bar
-         '(("^Author:[ \t]+\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)"
+         '(("^\\(?:Author\\|Commit\\):[ 
\t]+\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)"
             (1 'change-log-email))
            ;; Handle the case:
            ;; user: FirstName LastName <foo@bar>
-           ("^Author:[ \t]+\\([^<(]+?\\)[ 
\t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]"
+           ("^\\(?:Author\\|Commit\\):[ \t]+\\([^<(]+?\\)[ 
\t]*[(<]\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)[>)]"
             (1 'change-log-name)
             (2 'change-log-email))
            ("^ +\\(?:\\(?:[Aa]cked\\|[Ss]igned-[Oo]ff\\)-[Bb]y:\\)[ 
\t]+\\([A-Za-z0-9_.+-]+@[A-Za-z0-9_.-]+\\)"
@@ -1449,7 +1449,7 @@ log entries."
            ("^Merge: \\([0-9a-z]+\\) \\([0-9a-z]+\\)"
             (1 'change-log-acknowledgment)
             (2 'change-log-acknowledgment))
-           ("^\\(?:Date:   \\|AuthorDate: \\)\\(.+\\)" (1 'change-log-date))
+           ("^\\(?:Date:   \\|AuthorDate: \\|CommitDate: \\)\\(.+\\)" (1 
'change-log-date))
            ("^summary:[ \t]+\\(.+\\)" (1 'log-view-message)))))))
 
 
@@ -1674,7 +1674,8 @@ This requires git 1.8.4 or later, for the \"-L\" option 
of \"git log\"."
                                  (if branchp "branch" "tag"))))
          (if branchp
              (vc-git-command nil 0 nil "checkout" "-b" name
-                             (when (and start-point (not (eq start-point "")))
+                             (when (and start-point
+                                        (not (equal start-point "")))
                                start-point))
            (vc-git-command nil 0 nil "tag" name)))))
 
diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el
index 328d33040d..690c907c77 100644
--- a/lisp/vc/vc.el
+++ b/lisp/vc/vc.el
@@ -1135,7 +1135,7 @@ BEWARE: this function may change the current buffer."
       (vc-dir-deduce-fileset state-model-only-files))
      ((derived-mode-p 'dired-mode)
       (dired-vc-deduce-fileset state-model-only-files not-state-changing))
-     ((derived-mode-p 'diff-mode)
+     ((and (derived-mode-p 'diff-mode) (not buffer-file-name))
       (diff-vc-deduce-fileset))
      ((setq backend (vc-backend buffer-file-name))
       (if state-model-only-files
diff --git a/lisp/windmove.el b/lisp/windmove.el
index 00e76df0a0..4311f082de 100644
--- a/lisp/windmove.el
+++ b/lisp/windmove.el
@@ -776,7 +776,8 @@ Default value of MODIFIERS is `shift-super'."
 (defconst windmove--default-keybindings-type
   `(choice (const :tag "Don't bind" nil)
            (cons :tag "Bind using"
-                 (key-sequence :tag "Prefix")
+                 (choice (key-sequence :tag "Prefix")
+                         (const :tag "No Prefix" nil))
                  (set :tag "Modifier"
                       :greedy t
                       ;; See `(elisp) Keyboard Events'
diff --git a/lisp/window.el b/lisp/window.el
index a11293d372..a4a8421881 100644
--- a/lisp/window.el
+++ b/lisp/window.el
@@ -2162,17 +2162,14 @@ the font."
     (let* ((window-width (window-body-width window t))
           (font-width (window-font-width window face))
           (ncols (- (/ window-width font-width)
-                     (ceiling (line-number-display-width 'columns)))))
+                     (ceiling (line-number-display-width 'columns))))
+           (fringes (window-fringes window))
+           (lfringe (car fringes))
+           (rfringe (nth 1 fringes)))
       (if (and (display-graphic-p)
               overflow-newline-into-fringe
-               (not
-                (or (eq left-fringe-width 0)
-                    (and (null left-fringe-width)
-                         (= (frame-parameter nil 'left-fringe) 0))))
-               (not
-                (or (eq right-fringe-width 0)
-                    (and (null right-fringe-width)
-                         (= (frame-parameter nil 'right-fringe) 0)))))
+               (not (eq lfringe 0))
+               (not (eq rfringe 0)))
          ncols
         ;; FIXME: This should remove 1 more column when there are no
         ;; fringes, lines are truncated, and the window is hscrolled,
@@ -4636,7 +4633,7 @@ omitted in calls from `switch-to-next-buffer'."
                     (catch 'found
                       (dolist (regexp switch-to-prev-buffer-skip-regexp)
                         (when (string-match-p regexp (buffer-name buffer))
-                          (throw 'tag t)))))))))
+                          (throw 'found t)))))))))
 
 (defun switch-to-prev-buffer (&optional window bury-or-kill)
   "In WINDOW switch to previous buffer.
diff --git a/m4/explicit_bzero.m4 b/m4/explicit_bzero.m4
deleted file mode 100644
index 3b4ef8c3cc..0000000000
--- a/m4/explicit_bzero.m4
+++ /dev/null
@@ -1,23 +0,0 @@
-dnl Copyright 2017-2022 Free Software Foundation, Inc.
-dnl This file is free software; the Free Software Foundation
-dnl gives unlimited permission to copy and/or distribute it,
-dnl with or without modifications, as long as this notice is preserved.
-
-AC_DEFUN([gl_FUNC_EXPLICIT_BZERO],
-[
-  AC_REQUIRE([gl_STRING_H_DEFAULTS])
-
-  dnl Persuade glibc <string.h> to declare explicit_bzero.
-  AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
-
-  AC_CHECK_FUNCS_ONCE([explicit_bzero])
-  if test $ac_cv_func_explicit_bzero = no; then
-    HAVE_EXPLICIT_BZERO=0
-  fi
-])
-
-AC_DEFUN([gl_PREREQ_EXPLICIT_BZERO],
-[
-  AC_CHECK_FUNCS([explicit_memset])
-  AC_CHECK_FUNCS_ONCE([memset_s])
-])
diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4
index 1a8bf8b7cd..9ba977711f 100644
--- a/m4/gnulib-comp.m4
+++ b/m4/gnulib-comp.m4
@@ -82,7 +82,6 @@ AC_DEFUN([gl_EARLY],
   # Code from module errno:
   # Code from module euidaccess:
   # Code from module execinfo:
-  # Code from module explicit_bzero:
   # Code from module extensions:
   # Code from module extern-inline:
   # Code from module faccessat:
@@ -137,6 +136,7 @@ AC_DEFUN([gl_EARLY],
   # Code from module memmem-simple:
   # Code from module mempcpy:
   # Code from module memrchr:
+  # Code from module memset_explicit:
   # Code from module minmax:
   # Code from module mkostemp:
   # Code from module mktime:
@@ -285,12 +285,6 @@ AC_DEFUN([gl_INIT],
   gl_CONDITIONAL_HEADER([execinfo.h])
   AC_PROG_MKDIR_P
   gl_CONDITIONAL([GL_COND_OBJ_EXECINFO], [$GL_GENERATE_EXECINFO_H])
-  gl_FUNC_EXPLICIT_BZERO
-  gl_CONDITIONAL([GL_COND_OBJ_EXPLICIT_BZERO], [test $HAVE_EXPLICIT_BZERO = 0])
-  AM_COND_IF([GL_COND_OBJ_EXPLICIT_BZERO], [
-    gl_PREREQ_EXPLICIT_BZERO
-  ])
-  gl_STRING_MODULE_INDICATOR([explicit_bzero])
   AC_REQUIRE([gl_EXTERN_INLINE])
   gl_FUNC_FACCESSAT
   gl_CONDITIONAL([GL_COND_OBJ_FACCESSAT],
@@ -422,6 +416,12 @@ AC_DEFUN([gl_INIT],
     gl_PREREQ_MEMRCHR
   ])
   gl_STRING_MODULE_INDICATOR([memrchr])
+  gl_FUNC_MEMSET_EXPLICIT
+  gl_CONDITIONAL([GL_COND_OBJ_MEMSET_EXPLICIT], [test $HAVE_MEMSET_EXPLICIT = 
0])
+  AM_COND_IF([GL_COND_OBJ_MEMSET_EXPLICIT], [
+    gl_PREREQ_MEMSET_EXPLICIT
+  ])
+  gl_STRING_MODULE_INDICATOR([memset_explicit])
   gl_MINMAX
   gl_FUNC_MKOSTEMP
   gl_CONDITIONAL([GL_COND_OBJ_MKOSTEMP], [test $HAVE_MKOSTEMP = 0])
@@ -1248,7 +1248,6 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/euidaccess.c
   lib/execinfo.c
   lib/execinfo.in.h
-  lib/explicit_bzero.c
   lib/faccessat.c
   lib/fchmodat.c
   lib/fcntl.c
@@ -1318,6 +1317,7 @@ AC_DEFUN([gl_FILE_LIST], [
   lib/memmem.c
   lib/mempcpy.c
   lib/memrchr.c
+  lib/memset_explicit.c
   lib/mini-gmp-gnulib.c
   lib/mini-gmp.c
   lib/mini-gmp.h
@@ -1432,7 +1432,6 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/errno_h.m4
   m4/euidaccess.m4
   m4/execinfo.m4
-  m4/explicit_bzero.m4
   m4/extensions.m4
   m4/extern-inline.m4
   m4/faccessat.m4
@@ -1476,6 +1475,7 @@ AC_DEFUN([gl_FILE_LIST], [
   m4/memmem.m4
   m4/mempcpy.m4
   m4/memrchr.m4
+  m4/memset_explicit.m4
   m4/minmax.m4
   m4/mkostemp.m4
   m4/mktime.m4
diff --git a/m4/memset_explicit.m4 b/m4/memset_explicit.m4
new file mode 100644
index 0000000000..3d4dcb3095
--- /dev/null
+++ b/m4/memset_explicit.m4
@@ -0,0 +1,20 @@
+dnl Copyright 2022 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_MEMSET_EXPLICIT],
+[
+  AC_REQUIRE([gl_STRING_H_DEFAULTS])
+
+  AC_CHECK_FUNCS_ONCE([memset_explicit])
+  if test $ac_cv_func_memset_explicit = no; then
+    HAVE_MEMSET_EXPLICIT=0
+  fi
+])
+
+AC_DEFUN([gl_PREREQ_MEMSET_EXPLICIT],
+[
+  AC_CHECK_FUNCS([explicit_memset])
+  AC_CHECK_FUNCS_ONCE([memset_s])
+])
diff --git a/m4/string_h.m4 b/m4/string_h.m4
index 9e09b96e16..6069d4a752 100644
--- a/m4/string_h.m4
+++ b/m4/string_h.m4
@@ -5,7 +5,7 @@
 # gives unlimited permission to copy and/or distribute it,
 # with or without modifications, as long as this notice is preserved.
 
-# serial 34
+# serial 35
 
 # Written by Paul Eggert.
 
@@ -21,7 +21,8 @@ AC_DEFUN_ONCE([gl_STRING_H],
   dnl guaranteed by C89.
   gl_WARN_ON_USE_PREPARE([[#include <string.h>
     ]],
-    [ffsl ffsll memmem mempcpy memrchr rawmemchr stpcpy stpncpy strchrnul
+    [explicit_bzero ffsl ffsll memmem mempcpy memrchr memset_explicit
+     rawmemchr stpcpy stpncpy strchrnul
      strdup strncat strndup strnlen strpbrk strsep strcasestr strtok_r
      strerror_r strerrorname_np sigabbrev_np sigdescr_np strsignal strverscmp])
 
@@ -54,6 +55,7 @@ AC_DEFUN([gl_STRING_H_REQUIRE_DEFAULTS],
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMMEM])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMPCPY])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMRCHR])
+    gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MEMSET_EXPLICIT])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_RAWMEMCHR])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPCPY])
     gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_STPNCPY])
@@ -107,6 +109,7 @@ AC_DEFUN([gl_STRING_H_DEFAULTS],
   HAVE_FFSLL=1;                 AC_SUBST([HAVE_FFSLL])
   HAVE_DECL_MEMMEM=1;           AC_SUBST([HAVE_DECL_MEMMEM])
   HAVE_MEMPCPY=1;               AC_SUBST([HAVE_MEMPCPY])
+  HAVE_MEMSET_EXPLICIT=1;       AC_SUBST([HAVE_MEMSET_EXPLICIT])
   HAVE_DECL_MEMRCHR=1;          AC_SUBST([HAVE_DECL_MEMRCHR])
   HAVE_RAWMEMCHR=1;             AC_SUBST([HAVE_RAWMEMCHR])
   HAVE_STPCPY=1;                AC_SUBST([HAVE_STPCPY])
diff --git a/oldXMenu/ChangeLog.1 b/oldXMenu/ChangeLog.1
index ebbbcd2df2..b739a231f5 100644
--- a/oldXMenu/ChangeLog.1
+++ b/oldXMenu/ChangeLog.1
@@ -46,7 +46,7 @@
 
        * Makefile.in (mostlyclean, clean, distclean, maintainer-clean, tags):
        Declare as PHONY.
-       (boostrap-clean): New.
+       (bootstrap-clean): New.
 
 2013-10-24  Glenn Morris  <rgm@gnu.org>
 
diff --git a/src/ChangeLog.12 b/src/ChangeLog.12
index 7f77c0ca07..f455c4de38 100644
--- a/src/ChangeLog.12
+++ b/src/ChangeLog.12
@@ -10836,7 +10836,7 @@
        * gtkutil.c (xg_maybe_add_timer): Port to higher-res time stamps.
 
        * image.c (prepare_image_for_display, clear_image_cache)
-       (lookup_image): Port to higer-resolution time stamps.
+       (lookup_image): Port to higher-resolution time stamps.
 
        * keyboard.c (start_polling, bind_polling_period):
        Check for time stamp overflow.
diff --git a/src/ChangeLog.13 b/src/ChangeLog.13
index 91f8005ac5..0c4e2909ce 100644
--- a/src/ChangeLog.13
+++ b/src/ChangeLog.13
@@ -10579,7 +10579,7 @@
        (../src/$(OLDXMENU), $(OLDXMENU)): Remove.
        (temacs$(EXEEXT)): Depend on $(LIBXMENU), not stamp-oldxmenu.
        ($(lwlibdir)/liblw.a, $(oldXMenudir)/libXMenu11.a, FORCE): New targets.
-       (boostrap-clean): No need to remove stamp-oldxmenu.
+       (bootstrap-clean): No need to remove stamp-oldxmenu.
 
        Fix recently introduced bool vector overrun.
        This was due to an optimization that went awry.
diff --git a/src/alloc.c b/src/alloc.c
index 91a3237c57..a9eff612de 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -80,6 +80,37 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <valgrind/memcheck.h>
 #endif
 
+/* AddressSanitizer exposes additional functions for manually marking
+   memory as poisoned/unpoisoned.  When ASan is enabled and the needed
+   header is available, memory is poisoned when:
+
+   * An ablock is freed (lisp_align_free), or ablocks are initially
+   allocated (lisp_align_malloc).
+   * An interval_block is initially allocated (make_interval).
+   * A dead INTERVAL is put on the interval free list
+   (sweep_intervals).
+   * A sdata is marked as dead (sweep_strings, pin_string).
+   * An sblock is initially allocated (allocate_string_data).
+   * A string_block is initially allocated (allocate_string).
+   * A dead string is put on string_free_list (sweep_strings).
+   * A float_block is initially allocated (make_float).
+   * A dead float is put on float_free_list.
+   * A cons_block is initially allocated (Fcons).
+   * A dead cons is put on cons_free_list (sweep_cons).
+   * A dead vector is put on vector_free_list (setup_on_free_list),
+   or a new vector block is allocated (allocate_vector_from_block).
+   Accordingly, objects reused from the free list are unpoisoned.
+
+   This feature can be disabled wtih the run-time flag
+   `allow_user_poisoning' set to zero.  */
+#if ADDRESS_SANITIZER && defined HAVE_SANITIZER_ASAN_INTERFACE_H \
+  && !defined GC_ASAN_POISON_OBJECTS
+# define GC_ASAN_POISON_OBJECTS 1
+# include <sanitizer/asan_interface.h>
+#else
+# define GC_ASAN_POISON_OBJECTS 0
+#endif
+
 /* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects.
    We turn that on by default when ENABLE_CHECKING is defined;
    define GC_CHECK_MARKED_OBJECTS to zero to disable.  */
@@ -1156,6 +1187,16 @@ struct ablocks
   (1 & (intptr_t) ABLOCKS_BUSY (abase) ? abase : ((void **) (abase))[-1])
 #endif
 
+#if GC_ASAN_POISON_OBJECTS
+# define ASAN_POISON_ABLOCK(b) \
+  __asan_poison_memory_region (&(b)->x, sizeof ((b)->x))
+# define ASAN_UNPOISON_ABLOCK(b) \
+  __asan_unpoison_memory_region (&(b)->x, sizeof ((b)->x))
+#else
+# define ASAN_POISON_ABLOCK(b) ((void) 0)
+# define ASAN_UNPOISON_ABLOCK(b) ((void) 0)
+#endif
+
 /* The list of free ablock.   */
 static struct ablock *free_ablock;
 
@@ -1234,6 +1275,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
        {
          abase->blocks[i].abase = abase;
          abase->blocks[i].x.next_free = free_ablock;
+         ASAN_POISON_ABLOCK (&abase->blocks[i]);
          free_ablock = &abase->blocks[i];
        }
       intptr_t ialigned = aligned;
@@ -1246,6 +1288,7 @@ lisp_align_malloc (size_t nbytes, enum mem_type type)
       eassert ((intptr_t) ABLOCKS_BUSY (abase) == aligned);
     }
 
+  ASAN_UNPOISON_ABLOCK (free_ablock);
   abase = ABLOCK_ABASE (free_ablock);
   ABLOCKS_BUSY (abase)
     = (struct ablocks *) (2 + (intptr_t) ABLOCKS_BUSY (abase));
@@ -1277,6 +1320,7 @@ lisp_align_free (void *block)
 #endif
   /* Put on free list.  */
   ablock->x.next_free = free_ablock;
+  ASAN_POISON_ABLOCK (ablock);
   free_ablock = ablock;
   /* Update busy count.  */
   intptr_t busy = (intptr_t) ABLOCKS_BUSY (abase) - 2;
@@ -1289,9 +1333,12 @@ lisp_align_free (void *block)
       bool aligned = busy;
       struct ablock **tem = &free_ablock;
       struct ablock *atop = &abase->blocks[aligned ? ABLOCKS_SIZE : 
ABLOCKS_SIZE - 1];
-
       while (*tem)
        {
+#if GC_ASAN_POISON_OBJECTS
+         __asan_unpoison_memory_region (&(*tem)->x,
+                                        sizeof ((*tem)->x));
+#endif
          if (*tem >= (struct ablock *) abase && *tem < atop)
            {
              i++;
@@ -1420,6 +1467,24 @@ static int interval_block_index = INTERVAL_BLOCK_SIZE;
 
 static INTERVAL interval_free_list;
 
+#if GC_ASAN_POISON_OBJECTS
+# define ASAN_POISON_INTERVAL_BLOCK(b)         \
+  __asan_poison_memory_region ((b)->intervals, \
+                              sizeof ((b)->intervals))
+# define ASAN_UNPOISON_INTERVAL_BLOCK(b)         \
+  __asan_unpoison_memory_region ((b)->intervals, \
+                                sizeof ((b)->intervals))
+# define ASAN_POISON_INTERVAL(i) \
+  __asan_poison_memory_region ((i), sizeof (*(i)))
+# define ASAN_UNPOISON_INTERVAL(i) \
+  __asan_unpoison_memory_region ((i), sizeof (*(i)))
+#else
+# define ASAN_POISON_INTERVAL_BLOCK(b) ((void) 0)
+# define ASAN_UNPOISON_INTERVAL_BLOCK(b) ((void) 0)
+# define ASAN_POISON_INTERVAL(i) ((void) 0)
+# define ASAN_UNPOISON_INTERVAL(i) ((void) 0)
+#endif
+
 /* Return a new interval.  */
 
 INTERVAL
@@ -1432,6 +1497,7 @@ make_interval (void)
   if (interval_free_list)
     {
       val = interval_free_list;
+      ASAN_UNPOISON_INTERVAL (val);
       interval_free_list = INTERVAL_PARENT (interval_free_list);
     }
   else
@@ -1442,10 +1508,12 @@ make_interval (void)
            = lisp_malloc (sizeof *newi, false, MEM_TYPE_NON_LISP);
 
          newi->next = interval_block;
+         ASAN_POISON_INTERVAL_BLOCK (newi);
          interval_block = newi;
          interval_block_index = 0;
        }
       val = &interval_block->intervals[interval_block_index++];
+      ASAN_UNPOISON_INTERVAL (val);
     }
 
   MALLOC_UNBLOCK_INPUT;
@@ -1704,6 +1772,41 @@ init_strings (void)
   staticpro (&empty_multibyte_string);
 }
 
+#if GC_ASAN_POISON_OBJECTS
+/* Prepare s for denoting a free sdata struct, i.e, poison all bytes
+   in the flexible array member, except the first SDATA_OFFSET bytes.
+   This is only effective for strings of size n where n > sdata_size(n).
+ */
+# define ASAN_PREPARE_DEAD_SDATA(s, size)                          \
+  do {                                                             \
+    __asan_poison_memory_region ((s), sdata_size ((size)));        \
+    __asan_unpoison_memory_region (&(((s))->string),                 \
+                                  sizeof (struct Lisp_String *)); \
+    __asan_unpoison_memory_region (&SDATA_NBYTES ((s)),            \
+                                  sizeof (SDATA_NBYTES ((s))));   \
+   } while (false)
+/* Prepare s for storing string data for NBYTES bytes.  */
+# define ASAN_PREPARE_LIVE_SDATA(s, nbytes) \
+  __asan_unpoison_memory_region ((s), sdata_size ((nbytes)))
+# define ASAN_POISON_SBLOCK_DATA(b, size) \
+  __asan_poison_memory_region ((b)->data, (size))
+# define ASAN_POISON_STRING_BLOCK(b) \
+  __asan_poison_memory_region ((b)->strings, STRING_BLOCK_SIZE)
+# define ASAN_UNPOISON_STRING_BLOCK(b) \
+  __asan_unpoison_memory_region ((b)->strings, STRING_BLOCK_SIZE)
+# define ASAN_POISON_STRING(s) \
+  __asan_poison_memory_region ((s), sizeof (*(s)))
+# define ASAN_UNPOISON_STRING(s) \
+  __asan_unpoison_memory_region ((s), sizeof (*(s)))
+#else
+# define ASAN_PREPARE_DEAD_SDATA(s, size) ((void) 0)
+# define ASAN_PREPARE_LIVE_SDATA(s, nbytes) ((void) 0)
+# define ASAN_POISON_SBLOCK_DATA(b, size) ((void) 0)
+# define ASAN_POISON_STRING_BLOCK(b) ((void) 0)
+# define ASAN_UNPOISON_STRING_BLOCK(b) ((void) 0)
+# define ASAN_POISON_STRING(s) ((void) 0)
+# define ASAN_UNPOISON_STRING(s) ((void) 0)
+#endif
 
 #ifdef GC_CHECK_STRING_BYTES
 
@@ -1822,12 +1925,14 @@ allocate_string (void)
          NEXT_FREE_LISP_STRING (s) = string_free_list;
          string_free_list = s;
        }
+      ASAN_POISON_STRING_BLOCK (b);
     }
 
   check_string_free_list ();
 
   /* Pop a Lisp_String off the free-list.  */
   s = string_free_list;
+  ASAN_UNPOISON_STRING (s);
   string_free_list = NEXT_FREE_LISP_STRING (s);
 
   MALLOC_UNBLOCK_INPUT;
@@ -1887,6 +1992,7 @@ allocate_string_data (struct Lisp_String *s,
 #endif
 
       b = lisp_malloc (size + GC_STRING_EXTRA, clearit, MEM_TYPE_NON_LISP);
+      ASAN_POISON_SBLOCK_DATA (b, size);
 
 #ifdef DOUG_LEA_MALLOC
       if (!mmap_lisp_allowed_p ())
@@ -1908,6 +2014,8 @@ allocate_string_data (struct Lisp_String *s,
        {
          /* Not enough room in the current sblock.  */
          b = lisp_malloc (SBLOCK_SIZE, false, MEM_TYPE_NON_LISP);
+         ASAN_POISON_SBLOCK_DATA (b, SBLOCK_SIZE);
+
          data = b->data;
          b->next = NULL;
          b->next_free = data;
@@ -1920,10 +2028,19 @@ allocate_string_data (struct Lisp_String *s,
        }
 
       data = b->next_free;
+
       if (clearit)
-       memset (SDATA_DATA (data), 0, nbytes);
+       {
+#if GC_ASAN_POISON_OBJECTS
+         /* We are accessing SDATA_DATA (data) before it gets
+          * normally unpoisoned, so do it manually.  */
+         __asan_unpoison_memory_region (SDATA_DATA (data), nbytes);
+#endif
+         memset (SDATA_DATA (data), 0, nbytes);
+       }
     }
 
+  ASAN_PREPARE_LIVE_SDATA (data, nbytes);
   data->string = s;
   b->next_free = (sdata *) ((char *) data + needed + GC_STRING_EXTRA);
   eassert ((uintptr_t) b->next_free % alignof (sdata) == 0);
@@ -2015,12 +2132,16 @@ sweep_strings (void)
       int i, nfree = 0;
       struct Lisp_String *free_list_before = string_free_list;
 
+      ASAN_UNPOISON_STRING_BLOCK (b);
+
       next = b->next;
 
       for (i = 0; i < STRING_BLOCK_SIZE; ++i)
        {
          struct Lisp_String *s = b->strings + i;
 
+         ASAN_UNPOISON_STRING (s);
+
          if (s->u.s.data)
            {
              /* String was not on free-list before.  */
@@ -2057,6 +2178,8 @@ sweep_strings (void)
 
                  /* Put the string on the free-list.  */
                  NEXT_FREE_LISP_STRING (s) = string_free_list;
+                 ASAN_POISON_STRING (s);
+                 ASAN_PREPARE_DEAD_SDATA (data, SDATA_NBYTES (data));
                  string_free_list = s;
                  ++nfree;
                }
@@ -2065,6 +2188,8 @@ sweep_strings (void)
            {
              /* S was on the free-list before.  Put it there again.  */
              NEXT_FREE_LISP_STRING (s) = string_free_list;
+             ASAN_POISON_STRING (s);
+
              string_free_list = s;
              ++nfree;
            }
@@ -2191,6 +2316,7 @@ compact_small_strings (void)
                  if (from != to)
                    {
                      eassert (tb != b || to < from);
+                     ASAN_PREPARE_LIVE_SDATA (to, nbytes);
                      memmove (to, from, size + GC_STRING_EXTRA);
                      to->string->u.s.data = SDATA_DATA (to);
                    }
@@ -2542,6 +2668,7 @@ pin_string (Lisp_Object string)
       memcpy (s->u.s.data, data, size);
       old_sdata->string = NULL;
       SDATA_NBYTES (old_sdata) = size;
+      ASAN_PREPARE_DEAD_SDATA (old_sdata, size);
     }
   s->u.s.size_byte = -3;
 }
@@ -2599,6 +2726,24 @@ struct float_block
 #define XFLOAT_UNMARK(fptr) \
   UNSETMARKBIT (FLOAT_BLOCK (fptr), FLOAT_INDEX ((fptr)))
 
+#if GC_ASAN_POISON_OBJECTS
+# define ASAN_POISON_FLOAT_BLOCK(fblk)         \
+  __asan_poison_memory_region ((fblk)->floats, \
+                              sizeof ((fblk)->floats))
+# define ASAN_UNPOISON_FLOAT_BLOCK(fblk)         \
+  __asan_unpoison_memory_region ((fblk)->floats, \
+                                sizeof ((fblk)->floats))
+# define ASAN_POISON_FLOAT(p) \
+  __asan_poison_memory_region ((p), sizeof (struct Lisp_Float))
+# define ASAN_UNPOISON_FLOAT(p) \
+  __asan_unpoison_memory_region ((p), sizeof (struct Lisp_Float))
+#else
+# define ASAN_POISON_FLOAT_BLOCK(fblk) ((void) 0)
+# define ASAN_UNPOISON_FLOAT_BLOCK(fblk) ((void) 0)
+# define ASAN_POISON_FLOAT(p) ((void) 0)
+# define ASAN_UNPOISON_FLOAT(p) ((void) 0)
+#endif
+
 /* Current float_block.  */
 
 static struct float_block *float_block;
@@ -2623,6 +2768,7 @@ make_float (double float_value)
   if (float_free_list)
     {
       XSETFLOAT (val, float_free_list);
+      ASAN_UNPOISON_FLOAT (float_free_list);
       float_free_list = float_free_list->u.chain;
     }
   else
@@ -2633,9 +2779,11 @@ make_float (double float_value)
            = lisp_align_malloc (sizeof *new, MEM_TYPE_FLOAT);
          new->next = float_block;
          memset (new->gcmarkbits, 0, sizeof new->gcmarkbits);
+         ASAN_POISON_FLOAT_BLOCK (new);
          float_block = new;
          float_block_index = 0;
        }
+      ASAN_UNPOISON_FLOAT (&float_block->floats[float_block_index]);
       XSETFLOAT (val, &float_block->floats[float_block_index]);
       float_block_index++;
     }
@@ -2707,6 +2855,19 @@ static int cons_block_index = CONS_BLOCK_SIZE;
 
 static struct Lisp_Cons *cons_free_list;
 
+#if GC_ASAN_POISON_OBJECTS
+# define ASAN_POISON_CONS_BLOCK(b) \
+  __asan_poison_memory_region ((b)->conses, sizeof ((b)->conses))
+# define ASAN_POISON_CONS(p) \
+  __asan_poison_memory_region ((p), sizeof (struct Lisp_Cons))
+# define ASAN_UNPOISON_CONS(p) \
+  __asan_unpoison_memory_region ((p), sizeof (struct Lisp_Cons))
+#else
+# define ASAN_POISON_CONS_BLOCK(b) ((void) 0)
+# define ASAN_POISON_CONS(p) ((void) 0)
+# define ASAN_UNPOISON_CONS(p) ((void) 0)
+#endif
+
 /* Explicitly free a cons cell by putting it on the free-list.  */
 
 void
@@ -2717,6 +2878,7 @@ free_cons (struct Lisp_Cons *ptr)
   cons_free_list = ptr;
   ptrdiff_t nbytes = sizeof *ptr;
   tally_consing (-nbytes);
+  ASAN_POISON_CONS (ptr);
 }
 
 DEFUN ("cons", Fcons, Scons, 2, 2, 0,
@@ -2729,6 +2891,7 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
 
   if (cons_free_list)
     {
+      ASAN_UNPOISON_CONS (cons_free_list);
       XSETCONS (val, cons_free_list);
       cons_free_list = cons_free_list->u.s.u.chain;
     }
@@ -2739,10 +2902,12 @@ DEFUN ("cons", Fcons, Scons, 2, 2, 0,
          struct cons_block *new
            = lisp_align_malloc (sizeof *new, MEM_TYPE_CONS);
          memset (new->gcmarkbits, 0, sizeof new->gcmarkbits);
+         ASAN_POISON_CONS_BLOCK (new);
          new->next = cons_block;
          cons_block = new;
          cons_block_index = 0;
        }
+      ASAN_UNPOISON_CONS (&cons_block->conses[cons_block_index]);
       XSETCONS (val, &cons_block->conses[cons_block_index]);
       cons_block_index++;
     }
@@ -2997,6 +3162,19 @@ static struct large_vector *large_vectors;
 
 Lisp_Object zero_vector;
 
+#if GC_ASAN_POISON_OBJECTS
+# define ASAN_POISON_VECTOR_CONTENTS(v, bytes) \
+  __asan_poison_memory_region ((v)->contents, (bytes))
+# define ASAN_UNPOISON_VECTOR_CONTENTS(v, bytes) \
+  __asan_unpoison_memory_region ((v)->contents, (bytes))
+# define ASAN_UNPOISON_VECTOR_BLOCK(b) \
+  __asan_unpoison_memory_region ((b)->data, sizeof ((b)->data))
+#else
+# define ASAN_POISON_VECTOR_CONTENTS(v, bytes) ((void) 0)
+# define ASAN_UNPOISON_VECTOR_CONTENTS(v, bytes) ((void) 0)
+# define ASAN_UNPOISON_VECTOR_BLOCK(b) ((void) 0)
+#endif
+
 /* Common shortcut to setup vector on a free list.  */
 
 static void
@@ -3009,6 +3187,7 @@ setup_on_free_list (struct Lisp_Vector *v, ptrdiff_t 
nbytes)
   ptrdiff_t vindex = VINDEX (nbytes);
   eassert (vindex < VECTOR_MAX_FREE_LIST_INDEX);
   set_next_vector (v, vector_free_lists[vindex]);
+  ASAN_POISON_VECTOR_CONTENTS (v, nbytes - header_size);
   vector_free_lists[vindex] = v;
 }
 
@@ -3084,6 +3263,7 @@ allocate_vector_from_block (ptrdiff_t nbytes)
   if (vector_free_lists[index])
     {
       vector = vector_free_lists[index];
+      ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size);
       vector_free_lists[index] = next_vector (vector);
       return vector;
     }
@@ -3097,12 +3277,18 @@ allocate_vector_from_block (ptrdiff_t nbytes)
       {
        /* This vector is larger than requested.  */
        vector = vector_free_lists[index];
+       ASAN_UNPOISON_VECTOR_CONTENTS (vector, nbytes - header_size);
        vector_free_lists[index] = next_vector (vector);
 
        /* Excess bytes are used for the smaller vector,
           which should be set on an appropriate free list.  */
        restbytes = index * roundup_size + VBLOCK_BYTES_MIN - nbytes;
        eassert (restbytes % roundup_size == 0);
+#if GC_ASAN_POISON_OBJECTS
+       /* Ensure that accessing excess bytes does not trigger ASan.  */
+       __asan_unpoison_memory_region (ADVANCE (vector, nbytes),
+                                      restbytes);
+#endif
        setup_on_free_list (ADVANCE (vector, nbytes), restbytes);
        return vector;
       }
@@ -3278,6 +3464,7 @@ sweep_vectors (void)
       for (vector = (struct Lisp_Vector *) block->data;
           VECTOR_IN_BLOCK (vector, block); vector = next)
        {
+         ASAN_UNPOISON_VECTOR_BLOCK (block);
          if (XVECTOR_MARKED_P (vector))
            {
              XUNMARK_VECTOR (vector);
@@ -3653,6 +3840,23 @@ struct symbol_block
   struct symbol_block *next;
 };
 
+#if GC_ASAN_POISON_OBJECTS
+# define ASAN_POISON_SYMBOL_BLOCK(s) \
+  __asan_poison_memory_region ((s)->symbols, sizeof ((s)->symbols))
+# define ASAN_UNPOISON_SYMBOL_BLOCK(s) \
+  __asan_unpoison_memory_region ((s)->symbols, sizeof ((s)->symbols))
+# define ASAN_POISON_SYMBOL(sym) \
+  __asan_poison_memory_region ((sym), sizeof (*(sym)))
+# define ASAN_UNPOISON_SYMBOL(sym) \
+  __asan_unpoison_memory_region ((sym), sizeof (*(sym)))
+
+#else
+# define ASAN_POISON_SYMBOL_BLOCK(s) ((void) 0)
+# define ASAN_UNPOISON_SYMBOL_BLOCK(s) ((void) 0)
+# define ASAN_POISON_SYMBOL(sym) ((void) 0)
+# define ASAN_UNPOISON_SYMBOL(sym) ((void) 0)
+#endif
+
 /* Current symbol block and index of first unused Lisp_Symbol
    structure in it.  */
 
@@ -3705,6 +3909,7 @@ Its value is void, and its function definition and 
property list are nil.  */)
 
   if (symbol_free_list)
     {
+      ASAN_UNPOISON_SYMBOL (symbol_free_list);
       XSETSYMBOL (val, symbol_free_list);
       symbol_free_list = next_free_symbol (symbol_free_list);
     }
@@ -3714,10 +3919,13 @@ Its value is void, and its function definition and 
property list are nil.  */)
        {
          struct symbol_block *new
            = lisp_malloc (sizeof *new, false, MEM_TYPE_SYMBOL);
+         ASAN_POISON_SYMBOL_BLOCK (new);
          new->next = symbol_block;
          symbol_block = new;
          symbol_block_index = 0;
        }
+
+      ASAN_UNPOISON_SYMBOL (&symbol_block->symbols[symbol_block_index]);
       XSETSYMBOL (val, &symbol_block->symbols[symbol_block_index]);
       symbol_block_index++;
     }
@@ -4605,6 +4813,11 @@ static struct Lisp_String *
 live_string_holding (struct mem_node *m, void *p)
 {
   eassert (m->type == MEM_TYPE_STRING);
+#if GC_ASAN_POISON_OBJECTS
+  if (__asan_address_is_poisoned (p))
+    return NULL;
+#endif
+
   struct string_block *b = m->start;
   char *cp = p;
   ptrdiff_t offset = cp - (char *) &b->strings[0];
@@ -4621,6 +4834,10 @@ live_string_holding (struct mem_node *m, void *p)
          || off == offsetof (struct Lisp_String, u.s.data))
        {
          struct Lisp_String *s = p = cp -= off;
+#if GC_ASAN_POISON_OBJECTS
+         if (__asan_region_is_poisoned (s, sizeof (*s)))
+           return NULL;
+#endif
          if (s->u.s.data)
            return s;
        }
@@ -4642,6 +4859,11 @@ static struct Lisp_Cons *
 live_cons_holding (struct mem_node *m, void *p)
 {
   eassert (m->type == MEM_TYPE_CONS);
+#if GC_ASAN_POISON_OBJECTS
+  if (__asan_address_is_poisoned (p))
+    return NULL;
+#endif
+
   struct cons_block *b = m->start;
   char *cp = p;
   ptrdiff_t offset = cp - (char *) &b->conses[0];
@@ -4659,6 +4881,10 @@ live_cons_holding (struct mem_node *m, void *p)
          || off == offsetof (struct Lisp_Cons, u.s.u.cdr))
        {
          struct Lisp_Cons *s = p = cp -= off;
+#if GC_ASAN_POISON_OBJECTS
+         if (__asan_region_is_poisoned (s, sizeof (*s)))
+           return NULL;
+#endif
          if (!deadp (s->u.s.car))
            return s;
        }
@@ -4681,6 +4907,10 @@ static struct Lisp_Symbol *
 live_symbol_holding (struct mem_node *m, void *p)
 {
   eassert (m->type == MEM_TYPE_SYMBOL);
+#if GC_ASAN_POISON_OBJECTS
+  if (__asan_address_is_poisoned (p))
+    return NULL;
+#endif
   struct symbol_block *b = m->start;
   char *cp = p;
   ptrdiff_t offset = cp - (char *) &b->symbols[0];
@@ -4706,6 +4936,10 @@ live_symbol_holding (struct mem_node *m, void *p)
          || off == offsetof (struct Lisp_Symbol, u.s.plist))
        {
          struct Lisp_Symbol *s = p = cp -= off;
+#if GC_ASAN_POISON_OBJECTS
+         if (__asan_region_is_poisoned (s, sizeof (*s)))
+           return NULL;
+#endif
          if (!deadp (s->u.s.function))
            return s;
        }
@@ -4728,6 +4962,11 @@ static struct Lisp_Float *
 live_float_holding (struct mem_node *m, void *p)
 {
   eassert (m->type == MEM_TYPE_FLOAT);
+#if GC_ASAN_POISON_OBJECTS
+  if (__asan_address_is_poisoned (p))
+    return NULL;
+#endif
+
   struct float_block *b = m->start;
   char *cp = p;
   ptrdiff_t offset = cp - (char *) &b->floats[0];
@@ -4742,8 +4981,12 @@ live_float_holding (struct mem_node *m, void *p)
          && (b != float_block
              || offset / sizeof b->floats[0] < float_block_index))
        {
-         p = cp - off;
-         return p;
+         struct Lisp_Float *f = (struct Lisp_Float *) (cp - off);
+#if GC_ASAN_POISON_OBJECTS
+         if (__asan_region_is_poisoned (f, sizeof (*f)))
+           return NULL;
+#endif
+         return f;
        }
     }
   return NULL;
@@ -5319,7 +5562,8 @@ valid_lisp_object_p (Lisp_Object obj)
       if (valid <= 0)
        return valid;
 
-      if (SUBRP (obj))
+      /* Strings and conses produced by AUTO_STRING etc. all get here.  */
+      if (SUBRP (obj) || STRINGP (obj) || CONSP (obj))
        return 1;
 
       return 0;
@@ -6974,11 +7218,13 @@ sweep_conses (void)
                  struct Lisp_Cons *acons = &cblk->conses[pos];
                  if (!XCONS_MARKED_P (acons))
                     {
+                     ASAN_UNPOISON_CONS (&cblk->conses[pos]);
                       this_free++;
                       cblk->conses[pos].u.s.u.chain = cons_free_list;
                       cons_free_list = &cblk->conses[pos];
                       cons_free_list->u.s.car = dead_object ();
-                    }
+                     ASAN_POISON_CONS (&cblk->conses[pos]);
+                   }
                   else
                     {
                       num_used++;
@@ -6996,6 +7242,7 @@ sweep_conses (void)
         {
           *cprev = cblk->next;
           /* Unhook from the free list.  */
+         ASAN_UNPOISON_CONS (&cblk->conses[0]);
           cons_free_list = cblk->conses[0].u.s.u.chain;
           lisp_align_free (cblk);
         }
@@ -7022,6 +7269,7 @@ sweep_floats (void)
   for (struct float_block *fblk; (fblk = *fprev); )
     {
       int this_free = 0;
+      ASAN_UNPOISON_FLOAT_BLOCK (fblk);
       for (int i = 0; i < lim; i++)
        {
          struct Lisp_Float *afloat = &fblk->floats[i];
@@ -7029,6 +7277,7 @@ sweep_floats (void)
            {
              this_free++;
              fblk->floats[i].u.chain = float_free_list;
+             ASAN_POISON_FLOAT (&fblk->floats[i]);
              float_free_list = &fblk->floats[i];
            }
          else
@@ -7045,7 +7294,8 @@ sweep_floats (void)
         {
           *fprev = fblk->next;
           /* Unhook from the free list.  */
-          float_free_list = fblk->floats[0].u.chain;
+         ASAN_UNPOISON_FLOAT (&fblk->floats[0]);
+         float_free_list = fblk->floats[0].u.chain;
           lisp_align_free (fblk);
         }
       else
@@ -7071,13 +7321,14 @@ sweep_intervals (void)
   for (struct interval_block *iblk; (iblk = *iprev); )
     {
       int this_free = 0;
-
+      ASAN_UNPOISON_INTERVAL_BLOCK (iblk);
       for (int i = 0; i < lim; i++)
         {
           if (!iblk->intervals[i].gcmarkbit)
             {
               set_interval_parent (&iblk->intervals[i], interval_free_list);
               interval_free_list = &iblk->intervals[i];
+             ASAN_POISON_INTERVAL (&iblk->intervals[i]);
               this_free++;
             }
           else
@@ -7094,6 +7345,7 @@ sweep_intervals (void)
         {
           *iprev = iblk->next;
           /* Unhook from the free list.  */
+         ASAN_UNPOISON_INTERVAL (&iblk->intervals[0]);
           interval_free_list = INTERVAL_PARENT (&iblk->intervals[0]);
           lisp_free (iblk);
         }
@@ -7123,6 +7375,8 @@ sweep_symbols (void)
 
   for (sblk = symbol_block; sblk; sblk = *sprev)
     {
+      ASAN_UNPOISON_SYMBOL_BLOCK (sblk);
+
       int this_free = 0;
       struct Lisp_Symbol *sym = sblk->symbols;
       struct Lisp_Symbol *end = sym + lim;
@@ -7144,7 +7398,8 @@ sweep_symbols (void)
               set_next_free_symbol (sym, symbol_free_list);
               symbol_free_list = sym;
               symbol_free_list->u.s.function = dead_object ();
-              ++this_free;
+             ASAN_POISON_SYMBOL (sym);
+             ++this_free;
             }
           else
             {
@@ -7163,6 +7418,7 @@ sweep_symbols (void)
         {
           *sprev = sblk->next;
           /* Unhook from the free list.  */
+         ASAN_UNPOISON_SYMBOL (&sblk->symbols[0]);
           symbol_free_list = next_free_symbol (&sblk->symbols[0]);
           lisp_free (sblk);
         }
diff --git a/src/buffer.c b/src/buffer.c
index 71be7ed9e1..38c3150f2c 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -604,7 +604,6 @@ even if it is dead.  The return value is never nil.  */)
   set_buffer_intervals (b, NULL);
   BUF_UNCHANGED_MODIFIED (b) = 1;
   BUF_OVERLAY_UNCHANGED_MODIFIED (b) = 1;
-  BUF_CHARS_UNCHANGED_MODIFIED (b) = 1;
   BUF_END_UNCHANGED (b) = 0;
   BUF_BEG_UNCHANGED (b) = 0;
   *(BUF_GPT_ADDR (b)) = *(BUF_Z_ADDR (b)) = 0; /* Put an anchor '\0'.  */
@@ -1748,7 +1747,19 @@ other_buffer_safely (Lisp_Object buffer)
     if (candidate_buffer (buf, buffer))
       return buf;
 
-  return safe_call (1, Qget_scratch_buffer_create);
+  /* This function must return a valid buffer, since it is frequently
+     our last line of defense in the face of the expected buffers
+     becoming dead under our feet.  safe_call below could return nil
+     if recreating *scratch* in Lisp, which does some fancy stuff,
+     signals an error in some weird use case.  */
+  buf = safe_call (1, Qget_scratch_buffer_create);
+  if (NILP (buf))
+    {
+      AUTO_STRING (scratch, "*scratch*");
+      buf = Fget_buffer_create (scratch, Qnil);
+      Fset_buffer_major_mode (buf);
+    }
+  return buf;
 }
 
 DEFUN ("buffer-enable-undo", Fbuffer_enable_undo, Sbuffer_enable_undo,
@@ -3899,11 +3910,11 @@ the value is (point-min).  */)
 /* These functions are for debugging overlays.  */
 
 DEFUN ("overlay-lists", Foverlay_lists, Soverlay_lists, 0, 0, 0,
-       doc: /* Return a pair of lists giving all the overlays of the current 
buffer.
-The car has all the overlays before the overlay center;
-the cdr has all the overlays after the overlay center.
-Recentering overlays moves overlays between these lists.
-The lists you get are copies, so that changing them has no effect.
+       doc: /* Return a list giving all the overlays of the current buffer.
+
+For backward compatibility, the value is actually a list that
+holds another list; the overlays are in the inner list.
+The list you get is a copy, so that changing it has no effect.
 However, the overlays you get are the real objects that the buffer uses. */)
   (void)
 {
@@ -3919,7 +3930,12 @@ However, the overlays you get are the real objects that 
the buffer uses. */)
 DEFUN ("overlay-recenter", Foverlay_recenter, Soverlay_recenter, 1, 1, 0,
        doc: /* Recenter the overlays of the current buffer around position POS.
 That makes overlay lookup faster for positions near POS (but perhaps slower
-for positions far away from POS).  */)
+for positions far away from POS).
+
+Since Emacs 29.1, this function is a no-op, because the implementation
+of overlays changed and their lookup is now fast regardless of their
+position in the buffer.  In particular, this function no longer affects
+the value returned by `overlay-lists'.  */)
   (Lisp_Object pos)
 {
   CHECK_FIXNUM_COERCE_MARKER (pos);
diff --git a/src/buffer.h b/src/buffer.h
index 9ead875bcf..7c3d190314 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -149,18 +149,12 @@ enum { BEG = 1, BEG_BYTE = BEG };
 #define BUF_BEG_UNCHANGED(buf) ((buf)->text->beg_unchanged)
 #define BUF_END_UNCHANGED(buf) ((buf)->text->end_unchanged)
 
-#define BUF_CHARS_UNCHANGED_MODIFIED(buf) \
-  ((buf)->text->chars_unchanged_modified)
-
 #define UNCHANGED_MODIFIED \
   BUF_UNCHANGED_MODIFIED (current_buffer)
 #define OVERLAY_UNCHANGED_MODIFIED \
   BUF_OVERLAY_UNCHANGED_MODIFIED (current_buffer)
 #define BEG_UNCHANGED BUF_BEG_UNCHANGED (current_buffer)
 #define END_UNCHANGED BUF_END_UNCHANGED (current_buffer)
-
-#define CHARS_UNCHANGED_MODIFIED \
-  BUF_CHARS_UNCHANGED_MODIFIED (current_buffer)
 
 /* Functions to set PT in the current buffer, or another buffer.  */
 
@@ -274,11 +268,6 @@ struct buffer_text
        end_unchanged contain no useful information.  */
     modiff_count overlay_unchanged_modified;
 
-    /* CHARS_MODIFF as of last redisplay that finished.  It's used
-       when we only care about changes in actual buffer text, not in
-       any other kind of changes, like properties etc.  */
-    modiff_count chars_unchanged_modified;
-
     /* Properties of this buffer's text.  */
     INTERVAL intervals;
 
diff --git a/src/editfns.c b/src/editfns.c
index 90056886fe..659cf118d7 100644
--- a/src/editfns.c
+++ b/src/editfns.c
@@ -3279,18 +3279,18 @@ The other arguments are substituted into it to make the 
result, a string.
 The format control string may contain %-sequences meaning to substitute
 the next available argument, or the argument explicitly specified:
 
-%s means print a string argument.  Actually, prints any object, with `princ'.
-%d means print as signed number in decimal.
-%o means print a number in octal.
-%x means print a number in hex.
+%s means produce a string argument.  Actually, produces any object with 
`princ'.
+%d means produce as signed number in decimal.
+%o means produce a number in octal.
+%x means produce a number in hex.
 %X is like %x, but uses upper case.
-%e means print a number in exponential notation.
-%f means print a number in decimal-point notation.
-%g means print a number in exponential notation if the exponent would be
+%e means produce a number in exponential notation.
+%f means produce a number in decimal-point notation.
+%g means produce a number in exponential notation if the exponent would be
    less than -4 or greater than or equal to the precision (default: 6);
-   otherwise it prints in decimal-point notation.
-%c means print a number as a single character.
-%S means print any object as an s-expression (using `prin1').
+   otherwise it produces in decimal-point notation.
+%c means produce a number as a single character.
+%S means produce any object as an s-expression (using `prin1').
 
 The argument used for %d, %o, %x, %e, %f, %g or %c must be a number.
 %o, %x, and %X treat arguments as unsigned if `binary-as-unsigned' is t
@@ -3325,7 +3325,7 @@ included even if the precision is zero, and also forces 
trailing
 zeros after the decimal point to be left in place.
 
 The width specifier supplies a lower limit for the length of the
-printed representation.  The padding, if any, normally goes on the
+produced representation.  The padding, if any, normally goes on the
 left, but it goes on the right if the - flag is present.  The padding
 character is normally a space, but it is 0 if the 0 flag is present.
 The 0 flag is ignored if the - flag is present, or the format sequence
@@ -3334,7 +3334,7 @@ is something other than %d, %o, %x, %e, %f, and %g.
 For %e and %f sequences, the number after the "." in the precision
 specifier says how many decimal places to show; if zero, the decimal
 point itself is omitted.  For %g, the precision specifies how many
-significant digits to print; zero or omitted are treated as 1.
+significant digits to produce; zero or omitted are treated as 1.
 For %s and %S, the precision specifier truncates the string to the
 given width.
 
diff --git a/src/emacs.c b/src/emacs.c
index 9742dcd8a0..d156b77d95 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1927,6 +1927,12 @@ Using an Emacs configured with --with-x-toolkit=lucid 
does not have this problem
         Vcoding_system_hash_table.  */
       syms_of_coding ();       /* This should be after syms_of_fileio.  */
       init_frame_once ();       /* Before init_window_once.  */
+      /* init_window_once calls make_initial_frame, which calls
+        Fcurrent_time and bset_display_time, both of which allocate
+        bignums.  Without the following call to init_bignums, crashes
+        happen on Windows 9X after dumping when GC tries to free a
+        pointer allocated on the system heap.  */
+      init_bignum ();
       init_window_once ();     /* Init the window system.  */
 #ifdef HAVE_WINDOW_SYSTEM
       init_fringe_once ();     /* Swap bitmaps if necessary.  */
diff --git a/src/fileio.c b/src/fileio.c
index 92335b639c..e7c2af8142 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -134,6 +134,7 @@ static dev_t timestamp_file_system;
    is added here.  */
 static Lisp_Object Vwrite_region_annotation_buffers;
 
+static Lisp_Object emacs_readlinkat (int, char const *);
 static Lisp_Object file_name_directory (Lisp_Object);
 static bool a_write (int, Lisp_Object, ptrdiff_t, ptrdiff_t,
                     Lisp_Object *, struct coding_system *);
@@ -2219,7 +2220,7 @@ permissions.  */)
       report_file_error ("Copying permissions to", newname);
     }
 #else /* not WINDOWSNT */
-  ifd = emacs_open (SSDATA (encoded_file), O_RDONLY, 0);
+  ifd = emacs_open (SSDATA (encoded_file), O_RDONLY | O_NONBLOCK, 0);
 
   if (ifd < 0)
     report_file_error ("Opening input file", file);
@@ -2427,16 +2428,11 @@ DEFUN ("make-directory-internal", 
Fmake_directory_internal,
   (Lisp_Object directory)
 {
   const char *dir;
-  Lisp_Object handler;
   Lisp_Object encoded_dir;
 
   CHECK_STRING (directory);
   directory = Fexpand_file_name (directory, Qnil);
 
-  handler = Ffind_file_name_handler (directory, Qmake_directory_internal);
-  if (!NILP (handler))
-    return call2 (handler, Qmake_directory_internal, directory);
-
   encoded_dir = ENCODE_FILE (directory);
 
   dir = SSDATA (encoded_dir);
@@ -2710,31 +2706,19 @@ This is what happens in interactive use with M-x.  */)
     }
   if (dirp)
     call4 (Qcopy_directory, file, newname, Qt, Qnil);
-  else
-    {
-      Lisp_Object symlink_target
-       = (S_ISLNK (file_st.st_mode)
-          ? check_emacs_readlinkat (AT_FDCWD, file, SSDATA (encoded_file))
-          : Qnil);
-      if (!NILP (symlink_target))
-       Fmake_symbolic_link (symlink_target, newname, ok_if_already_exists);
-      else if (S_ISFIFO (file_st.st_mode))
-       {
-         /* If it's a FIFO, calling `copy-file' will hang if it's a
-            inter-file system move, so do it here.  (It will signal
-            an error in that case, but it won't hang in any case.)  */
-         if (!NILP (ok_if_already_exists))
-           barf_or_query_if_file_exists (newname, false,
-                                         "rename to it",
-                                         FIXNUMP (ok_if_already_exists),
-                                         false);
-         if (rename (SSDATA (encoded_file), SSDATA (encoded_newname)) != 0)
-           report_file_errno ("Renaming", list2 (file, newname), errno);
-         return Qnil;
-       }
+  else if (S_ISREG (file_st.st_mode))
+    Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt);
+  else if (S_ISLNK (file_st.st_mode))
+    {
+      Lisp_Object target = emacs_readlinkat (AT_FDCWD,
+                                            SSDATA (encoded_file));
+      if (!NILP (target))
+       Fmake_symbolic_link (target, newname, ok_if_already_exists);
       else
-       Fcopy_file (file, newname, ok_if_already_exists, Qt, Qt, Qt);
+       report_file_error ("Renaming", list2 (file, newname));
     }
+  else
+    report_file_errno ("Renaming", list2 (file, newname), rename_errno);
 
   specpdl_ref count = SPECPDL_INDEX ();
   specbind (Qdelete_by_moving_to_trash, Qnil);
diff --git a/src/fns.c b/src/fns.c
index d8d8b104e1..63e5fd56f0 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -497,8 +497,13 @@ Symbols are also allowed; their print names are used 
instead.  */)
          int ws = sizeof (word_t);
          const word_t *w1 = (const word_t *) SDATA (string1);
          const word_t *w2 = (const word_t *) SDATA (string2);
-         while (b < nb - ws + 1 && w1[b / ws] == w2[b / ws])
-           b += ws;
+         while (b < nb - ws + 1)
+           {
+             if (UNALIGNED_LOAD_SIZE (w1, b / ws)
+                 != UNALIGNED_LOAD_SIZE (w2, b / ws))
+               break;
+             b += ws;
+           }
        }
 
       /* Scan forward to the differing byte.  */
@@ -3938,7 +3943,7 @@ system.
 If the region can't be decoded, signal an error and don't modify the buffer.
 Optional third argument BASE64URL determines whether to use the URL variant
 of the base 64 encoding, as defined in RFC 4648.
-If optional fourth argument INGORE-INVALID is non-nil invalid characters
+If optional fourth argument IGNORE-INVALID is non-nil invalid characters
 are ignored instead of signaling an error.  */)
      (Lisp_Object beg, Lisp_Object end, Lisp_Object base64url,
       Lisp_Object ignore_invalid)
diff --git a/src/frame.h b/src/frame.h
index d6fd62b2ac..dcd32036b8 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1718,7 +1718,6 @@ extern void x_wm_set_icon_position (struct frame *, int, 
int);
 #if !defined USE_X_TOOLKIT
 extern const char *x_get_resource_string (const char *, const char *);
 #endif
-extern void x_sync (struct frame *);
 #endif /* HAVE_X_WINDOWS */
 
 #if !defined (HAVE_NS) && !defined (HAVE_PGTK)
diff --git a/src/gnutls.c b/src/gnutls.c
index 7f0aaf85a4..4093865cae 100644
--- a/src/gnutls.c
+++ b/src/gnutls.c
@@ -2282,7 +2282,7 @@ gnutls_symmetric_aead (bool encrypting, 
gnutls_cipher_algorithm_t gca,
   Lisp_Object output;
   if (GNUTLS_E_SUCCESS <= ret)
     output = make_unibyte_string (storage, storage_length);
-  explicit_bzero (storage, storage_length);
+  memset_explicit (storage, 0, storage_length);
   gnutls_aead_cipher_deinit (acipher);
 
   if (ret < GNUTLS_E_SUCCESS)
diff --git a/src/gtkutil.c b/src/gtkutil.c
index a6bba096a4..592bb49774 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -2103,7 +2103,7 @@ xg_frame_restack (struct frame *f1, struct frame *f2, 
bool above_flag)
 
       gdk_window_restack (gwin1, gwin2, above_flag);
 #ifndef HAVE_PGTK
-      x_sync (f1);
+      XSync (FRAME_X_DISPLAY (f1), False);
 #else
       gdk_flush ();
 #endif
@@ -4793,7 +4793,7 @@ xg_update_scrollbar_pos (struct frame *f,
          here to get some events.  */
 
 #ifndef HAVE_PGTK
-      x_sync (f);
+      XSync (FRAME_X_DISPLAY (f), False);
 #else
       gdk_flush ();
 #endif
@@ -4894,7 +4894,7 @@ xg_update_horizontal_scrollbar_pos (struct frame *f,
       }
 
 #ifndef HAVE_PGTK
-      x_sync (f);
+      XSync (FRAME_X_DISPLAY (f), False);
 #else
       gdk_flush ();
 #endif
diff --git a/src/image.c b/src/image.c
index 8403c4b7eb..63561460e6 100644
--- a/src/image.c
+++ b/src/image.c
@@ -11311,6 +11311,15 @@ svg_load_image (struct frame *f, struct image *img, 
char *contents,
                                                    img->face_font_size);
          viewbox_height = svg_css_length_to_pixels (iheight, dpi,
                                                     img->face_font_size);
+
+         /* Here one dimension could be zero because in percent unit.
+            So calculate this dimension with the other.  */
+         if (! (0 < viewbox_width) && (iwidth.unit == RSVG_UNIT_PERCENT))
+           viewbox_width = (viewbox_height * viewbox.width / viewbox.height)
+             * iwidth.length;
+         else if (! (0 < viewbox_height) && (iheight.unit == 
RSVG_UNIT_PERCENT))
+           viewbox_height = (viewbox_width * viewbox.height / viewbox.width)
+             * iheight.length;
        }
       else if (has_width && has_viewbox)
        {
diff --git a/src/itree.c b/src/itree.c
index 04fa9e827a..688d5c8247 100644
--- a/src/itree.c
+++ b/src/itree.c
@@ -15,7 +15,7 @@ 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 <http://www.gnu.org/licenses/>.  */
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <math.h>
@@ -1376,7 +1376,7 @@ itree_iterator_first_node (struct itree_tree *tree,
   return node;
 }
 
-/* Start a iterator enumerating all intervals in [BEGIN,END) in the
+/* Start an iterator enumerating all intervals in [BEGIN,END) in the
    given ORDER.  */
 
 struct itree_iterator *
diff --git a/src/itree.h b/src/itree.h
index 248ea9b84d..f1e2bf3bfd 100644
--- a/src/itree.h
+++ b/src/itree.h
@@ -15,7 +15,7 @@ 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 <http://www.gnu.org/licenses/>.  */
+along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #ifndef ITREE_H
 #define ITREE_H
diff --git a/src/lisp.h b/src/lisp.h
index 63cc07d43f..518c2e6f99 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -5398,6 +5398,26 @@ __lsan_ignore_object (void const *p)
 }
 #endif
 
+/* If built with USE_SANITIZER_UNALIGNED_LOAD defined, use compiler
+   provided ASan functions to perform unaligned loads, allowing ASan
+   to catch bugs which it might otherwise miss.  */
+#if defined HAVE_SANITIZER_COMMON_INTERFACE_DEFS_H \
+  && defined ADDRESS_SANITIZER                     \
+  && defined USE_SANITIZER_UNALIGNED_LOAD
+# include <sanitizer/common_interface_defs.h>
+# if (SIZE_MAX == UINT64_MAX)
+#  define UNALIGNED_LOAD_SIZE(a, i) \
+   (size_t) __sanitizer_unaligned_load64 ((void *) ((a) + (i)))
+# elif (SIZE_MAX == UINT32_MAX)
+#  define UNALIGNED_LOAD_SIZE(a, i) \
+   (size_t) __sanitizer_unaligned_load32 ((void *) ((a) + (i)))
+# else
+#  define UNALIGNED_LOAD_SIZE(a, i) *((a) + (i))
+# endif
+#else
+# define UNALIGNED_LOAD_SIZE(a, i) *((a) + (i))
+#endif
+
 extern void xputenv (const char *);
 
 extern char *egetenv_internal (const char *, ptrdiff_t);
diff --git a/src/lread.c b/src/lread.c
index bd3073aef0..b28987551e 100644
--- a/src/lread.c
+++ b/src/lread.c
@@ -3377,7 +3377,7 @@ read_bool_vector (Lisp_Object readcharfun)
          break;
        }
       if (INT_MULTIPLY_WRAPV (length, 10, &length)
-         | INT_ADD_WRAPV (length, c - '0', &length))
+         || INT_ADD_WRAPV (length, c - '0', &length))
        invalid_syntax ("#&", readcharfun);
     }
 
@@ -3423,7 +3423,7 @@ skip_lazy_string (Lisp_Object readcharfun)
          break;
        }
       if (INT_MULTIPLY_WRAPV (nskip, 10, &nskip)
-         | INT_ADD_WRAPV (nskip, c - '0', &nskip))
+         || INT_ADD_WRAPV (nskip, c - '0', &nskip))
        invalid_syntax ("#@", readcharfun);
       digits++;
       if (digits == 2 && nskip == 0)
@@ -5266,15 +5266,6 @@ to the specified file name if a suffix is allowed or 
required.  */);
   Vload_suffixes =
     Fcons (build_pure_c_string (MODULES_SECONDARY_SUFFIX), Vload_suffixes);
 #endif
-
-  DEFVAR_LISP ("dynamic-library-suffixes", Vdynamic_library_suffixes,
-              doc: /* A list of suffixes for loadable dynamic libraries.  */);
-  Vdynamic_library_suffixes =
-    Fcons (build_pure_c_string (DYNAMIC_LIB_SECONDARY_SUFFIX), Qnil);
-  Vdynamic_library_suffixes =
-    Fcons (build_pure_c_string (DYNAMIC_LIB_SUFFIX),
-          Vdynamic_library_suffixes);
-
 #endif
   DEFVAR_LISP ("module-file-suffix", Vmodule_file_suffix,
               doc: /* Suffix of loadable module file, or nil if modules are 
not supported.  */);
@@ -5283,6 +5274,20 @@ to the specified file name if a suffix is allowed or 
required.  */);
 #else
   Vmodule_file_suffix = Qnil;
 #endif
+
+  DEFVAR_LISP ("dynamic-library-suffixes", Vdynamic_library_suffixes,
+              doc: /* A list of suffixes for loadable dynamic libraries.  */);
+
+#ifndef MSDOS
+  Vdynamic_library_suffixes
+    = Fcons (build_pure_c_string (DYNAMIC_LIB_SECONDARY_SUFFIX), Qnil);
+  Vdynamic_library_suffixes
+    = Fcons (build_pure_c_string (DYNAMIC_LIB_SUFFIX),
+            Vdynamic_library_suffixes);
+#else
+  Vdynamic_library_suffixes = Qnil;
+#endif
+
   DEFVAR_LISP ("load-file-rep-suffixes", Vload_file_rep_suffixes,
               doc: /* List of suffixes that indicate representations of \
 the same file.
diff --git a/src/pdumper.c b/src/pdumper.c
index 2f1cbf7b88..af8bbe6393 100644
--- a/src/pdumper.c
+++ b/src/pdumper.c
@@ -2809,7 +2809,6 @@ dump_buffer (struct dump_context *ctx, const struct 
buffer *in_buffer)
       DUMP_FIELD_COPY (out, buffer, own_text.end_unchanged);
       DUMP_FIELD_COPY (out, buffer, own_text.unchanged_modified);
       DUMP_FIELD_COPY (out, buffer, own_text.overlay_unchanged_modified);
-      DUMP_FIELD_COPY (out, buffer, own_text.chars_unchanged_modified);
       if (buffer->own_text.intervals)
         dump_field_fixup_later (ctx, out, buffer, &buffer->own_text.intervals);
       dump_field_lv_rawptr (ctx, out, buffer, &buffer->own_text.markers,
diff --git a/src/sysdep.c b/src/sysdep.c
index 736723bdf3..8402ffe308 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -2653,10 +2653,11 @@ emacs_perror (char const *message)
 int
 renameat_noreplace (int srcfd, char const *src, int dstfd, char const *dst)
 {
-#if defined SYS_renameat2 && defined RENAME_NOREPLACE
-  return syscall (SYS_renameat2, srcfd, src, dstfd, dst, RENAME_NOREPLACE);
-#elif defined CYGWIN && defined RENAME_NOREPLACE
+#if HAVE_RENAMEAT2 && defined RENAME_NOREPLACE
   return renameat2 (srcfd, src, dstfd, dst, RENAME_NOREPLACE);
+#elif defined SYS_renameat2 && defined RENAME_NOREPLACE
+  /* Linux kernel 3.15 (2014) or later, with glibc 2.27 (2018) or earlier.  */
+  return syscall (SYS_renameat2, srcfd, src, dstfd, dst, RENAME_NOREPLACE);
 #elif defined RENAME_EXCL
   return renameatx_np (srcfd, src, dstfd, dst, RENAME_EXCL);
 #else
diff --git a/src/timefns.c b/src/timefns.c
index 9beec1ce38..dcc6403fd9 100644
--- a/src/timefns.c
+++ b/src/timefns.c
@@ -40,6 +40,10 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include <stdio.h>
 #include <stdlib.h>
 
+#ifdef WINDOWSNT
+extern clock_t sys_clock (void);
+#endif
+
 #ifdef HAVE_TIMEZONE_T
 # include <sys/param.h>
 # if defined __NetBSD_Version__ && __NetBSD_Version__ < 700000000
diff --git a/src/treesit.c b/src/treesit.c
index 7c956a90b4..9fa88b48dc 100644
--- a/src/treesit.c
+++ b/src/treesit.c
@@ -52,7 +52,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #undef ts_node_named_descendant_for_byte_range
 #undef ts_node_next_named_sibling
 #undef ts_node_next_sibling
-#undef ts_node_parent
 #undef ts_node_prev_named_sibling
 #undef ts_node_prev_sibling
 #undef ts_node_start_byte
@@ -76,7 +75,9 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #undef ts_query_predicates_for_pattern
 #undef ts_query_string_value_for_id
 #undef ts_set_allocator
+#undef ts_tree_cursor_copy
 #undef ts_tree_cursor_current_node
+#undef ts_tree_cursor_delete
 #undef ts_tree_cursor_goto_first_child
 #undef ts_tree_cursor_goto_next_sibling
 #undef ts_tree_cursor_goto_parent
@@ -109,7 +110,6 @@ DEF_DLL_FN (TSNode, ts_node_named_descendant_for_byte_range,
            (TSNode, uint32_t, uint32_t));
 DEF_DLL_FN (TSNode, ts_node_next_named_sibling, (TSNode));
 DEF_DLL_FN (TSNode, ts_node_next_sibling, (TSNode));
-DEF_DLL_FN (TSNode, ts_node_parent, (TSNode));
 DEF_DLL_FN (TSNode, ts_node_prev_named_sibling, (TSNode));
 DEF_DLL_FN (TSNode, ts_node_prev_sibling, (TSNode));
 DEF_DLL_FN (uint32_t, ts_node_start_byte, (TSNode));
@@ -143,7 +143,9 @@ DEF_DLL_FN (const char *, ts_query_string_value_for_id,
            (const TSQuery *, uint32_t, uint32_t *));
 DEF_DLL_FN (void, ts_set_allocator,
            (void *(*)(size_t), void *(*)(size_t, size_t), void *(*)(void *, 
size_t), void (*)(void *)));
+DEF_DLL_FN (TSTreeCursor, ts_tree_cursor_copy, (const TSTreeCursor *));
 DEF_DLL_FN (TSNode, ts_tree_cursor_current_node, (const TSTreeCursor *));
+DEF_DLL_FN (void, ts_tree_cursor_delete, (const TSTreeCursor *));
 DEF_DLL_FN (bool, ts_tree_cursor_goto_first_child, (TSTreeCursor *));
 DEF_DLL_FN (bool, ts_tree_cursor_goto_next_sibling, (TSTreeCursor *));
 DEF_DLL_FN (bool, ts_tree_cursor_goto_parent, (TSTreeCursor *));
@@ -182,7 +184,6 @@ init_treesit_functions (void)
   LOAD_DLL_FN (library, ts_node_named_descendant_for_byte_range);
   LOAD_DLL_FN (library, ts_node_next_named_sibling);
   LOAD_DLL_FN (library, ts_node_next_sibling);
-  LOAD_DLL_FN (library, ts_node_parent);
   LOAD_DLL_FN (library, ts_node_prev_named_sibling);
   LOAD_DLL_FN (library, ts_node_prev_sibling);
   LOAD_DLL_FN (library, ts_node_start_byte);
@@ -206,7 +207,9 @@ init_treesit_functions (void)
   LOAD_DLL_FN (library, ts_query_predicates_for_pattern);
   LOAD_DLL_FN (library, ts_query_string_value_for_id);
   LOAD_DLL_FN (library, ts_set_allocator);
+  LOAD_DLL_FN (library, ts_tree_cursor_copy);
   LOAD_DLL_FN (library, ts_tree_cursor_current_node);
+  LOAD_DLL_FN (library, ts_tree_cursor_delete);
   LOAD_DLL_FN (library, ts_tree_cursor_goto_first_child);
   LOAD_DLL_FN (library, ts_tree_cursor_goto_next_sibling);
   LOAD_DLL_FN (library, ts_tree_cursor_goto_parent);
@@ -239,7 +242,6 @@ init_treesit_functions (void)
 #define ts_node_named_descendant_for_byte_range 
fn_ts_node_named_descendant_for_byte_range
 #define ts_node_next_named_sibling fn_ts_node_next_named_sibling
 #define ts_node_next_sibling fn_ts_node_next_sibling
-#define ts_node_parent fn_ts_node_parent
 #define ts_node_prev_named_sibling fn_ts_node_prev_named_sibling
 #define ts_node_prev_sibling fn_ts_node_prev_sibling
 #define ts_node_start_byte fn_ts_node_start_byte
@@ -263,7 +265,9 @@ init_treesit_functions (void)
 #define ts_query_predicates_for_pattern fn_ts_query_predicates_for_pattern
 #define ts_query_string_value_for_id fn_ts_query_string_value_for_id
 #define ts_set_allocator fn_ts_set_allocator
+#define ts_tree_cursor_copy fn_ts_tree_cursor_copy
 #define ts_tree_cursor_current_node fn_ts_tree_cursor_current_node
+#define ts_tree_cursor_delete fn_ts_tree_cursor_delete
 #define ts_tree_cursor_goto_first_child fn_ts_tree_cursor_goto_first_child
 #define ts_tree_cursor_goto_next_sibling fn_ts_tree_cursor_goto_next_sibling
 #define ts_tree_cursor_goto_parent fn_ts_tree_cursor_goto_parent
@@ -288,7 +292,7 @@ init_treesit_functions (void)
      slow enough to make insignificant any performance advantages from
      using the cursor.  Not exposing the cursor also minimizes the
      number of new types this adds to Emacs Lisp; currently, this adds
-     only the parser and node types.
+     only the parser, node, and compiled query types.
 
    - Because updating the change is handled on the C level as each
      change is made in the buffer, there is no way for Lisp to update
@@ -384,7 +388,18 @@ init_treesit_functions (void)
    mysteriously drops.  3) what if a user uses so many stuff that the
    default cache size (20) is not enough and we end up thrashing?
    These are all imaginary scenarios but they are not impossible
-   :-) */
+   :-)
+
+   Parsers in indirect buffers: We make indirect buffers to share the
+   parser of its base buffer.  Indirect buffers and their base buffer
+   share the same buffer content but not other buffer attributes.  If
+   they have separate parser lists, changes made in an indirect buffer
+   will only update parsers of that indirect buffer, and not parsers
+   in the base buffer or other indirect buffers, and vice versa.  We
+   could keep track of all the base and indirect buffers, and update
+   all of their parsers, but ultimately decide to take a simpler
+   approach, which is to make indirect buffers share their base
+   buffer's parser list.  The discussion can be found in bug#59693.  */
 
 
 /*** Initialization */
@@ -697,9 +712,10 @@ void
 treesit_record_change (ptrdiff_t start_byte, ptrdiff_t old_end_byte,
                       ptrdiff_t new_end_byte)
 {
-  Lisp_Object parser_list;
-
-  parser_list = BVAR (current_buffer, ts_parser_list);
+  struct buffer *base_buffer = current_buffer;
+  if (current_buffer->base_buffer)
+    base_buffer = current_buffer->base_buffer;
+  Lisp_Object parser_list = BVAR (base_buffer, ts_parser_list);
 
   FOR_EACH_TAIL_SAFE (parser_list)
     {
@@ -1252,12 +1268,16 @@ DEFUN ("treesit-parser-create",
        1, 3, 0,
        doc: /* Create and return a parser in BUFFER for LANGUAGE.
 
-The parser is automatically added to BUFFER's parser list, as
-returned by `treesit-parser-list'.
-LANGUAGE is a language symbol.  If BUFFER is nil or omitted, it
-defaults to the current buffer.  If BUFFER already has a parser for
-LANGUAGE, return that parser, but if NO-REUSE is non-nil, always
-create a new parser.  */)
+The parser is automatically added to BUFFER's parser list, as returned
+by `treesit-parser-list'.  LANGUAGE is a language symbol.  If BUFFER
+is nil or omitted, it defaults to the current buffer.  If BUFFER
+already has a parser for LANGUAGE, return that parser, but if NO-REUSE
+is non-nil, always create a new parser.
+
+If that buffer is an indirect buffer, its base buffer is used instead.
+That is, indirect buffers use their base buffer's parsers.  Lisp
+programs should widen as necessary should they want to use a parser in
+an indirect buffer.  */)
   (Lisp_Object language, Lisp_Object buffer, Lisp_Object no_reuse)
 {
   treesit_initialize ();
@@ -1271,16 +1291,21 @@ create a new parser.  */)
       CHECK_BUFFER (buffer);
       buf = XBUFFER (buffer);
     }
+  if (buf->base_buffer)
+    buf = buf->base_buffer;
+
   treesit_check_buffer_size (buf);
 
   /* See if we can reuse a parser.  */
-  for (Lisp_Object tail = BVAR (buf, ts_parser_list);
-       NILP (no_reuse) && !NILP (tail);
-       tail = XCDR (tail))
+  if (NILP (no_reuse))
     {
-      struct Lisp_TS_Parser *parser = XTS_PARSER (XCAR (tail));
-      if (EQ (parser->language_symbol, language))
-       return XCAR (tail);
+      Lisp_Object tail = BVAR (buf, ts_parser_list);
+      FOR_EACH_TAIL (tail)
+      {
+       struct Lisp_TS_Parser *parser = XTS_PARSER (XCAR (tail));
+       if (EQ (parser->language_symbol, language))
+         return XCAR (tail);
+      }
     }
 
   /* Load language.  */
@@ -1329,7 +1354,10 @@ DEFUN ("treesit-parser-list",
        Ftreesit_parser_list, Streesit_parser_list,
        0, 1, 0,
        doc: /* Return BUFFER's parser list.
-BUFFER defaults to the current buffer.  */)
+
+BUFFER defaults to the current buffer.  If that buffer is an indirect
+buffer, its base buffer is used instead.  That is, indirect buffers
+use their base buffer's parsers.  */)
   (Lisp_Object buffer)
 {
   struct buffer *buf;
@@ -1340,6 +1368,9 @@ BUFFER defaults to the current buffer.  */)
       CHECK_BUFFER (buffer);
       buf = XBUFFER (buffer);
     }
+  if (buf->base_buffer)
+    buf = buf->base_buffer;
+
   /* Return a fresh list so messing with that list doesn't affect our
      internal data.  */
   Lisp_Object return_list = Qnil;
@@ -1501,9 +1532,9 @@ buffer.  */)
       for (int idx = 0; !NILP (ranges); idx++, ranges = XCDR (ranges))
        {
          Lisp_Object range = XCAR (ranges);
-         EMACS_INT beg_byte = buf_charpos_to_bytepos (buffer,
+         ptrdiff_t beg_byte = buf_charpos_to_bytepos (buffer,
                                                       XFIXNUM (XCAR (range)));
-         EMACS_INT end_byte = buf_charpos_to_bytepos (buffer,
+         ptrdiff_t end_byte = buf_charpos_to_bytepos (buffer,
                                                       XFIXNUM (XCDR (range)));
          /* Shouldn't violate assertion since we just checked for
             buffer size at the beginning of this function.  */
@@ -1642,6 +1673,17 @@ treesit_check_node (Lisp_Object obj)
     xsignal1 (Qtreesit_node_outdated, obj);
 }
 
+/* Checks that OBJ is a positive integer and it is within the visible
+   portion of BUF. */
+static void
+treesit_check_position (Lisp_Object obj, struct buffer *buf)
+{
+  treesit_check_positive_integer (obj);
+  ptrdiff_t pos = XFIXNUM (obj);
+  if (pos < BUF_BEGV (buf) || pos > BUF_ZV (buf))
+    xsignal1 (Qargs_out_of_range, obj);
+}
+
 bool
 treesit_node_uptodate_p (Lisp_Object obj)
 {
@@ -1720,6 +1762,8 @@ If NODE is nil, return nil.  */)
   return build_string (string);
 }
 
+static TSTreeCursor treesit_cursor_helper (TSNode, Lisp_Object);
+
 DEFUN ("treesit-node-parent",
        Ftreesit_node_parent, Streesit_node_parent, 1, 1, 0,
        doc: /* Return the immediate parent of NODE.
@@ -1730,13 +1774,18 @@ Return nil if NODE has no parent.  If NODE is nil, 
return nil.  */)
   treesit_check_node (node);
   treesit_initialize ();
 
-  TSNode treesit_node = XTS_NODE (node)->node;
-  TSNode parent = ts_node_parent (treesit_node);
-
-  if (ts_node_is_null (parent))
-    return Qnil;
+  Lisp_Object return_value = Qnil;
 
-  return make_treesit_node (XTS_NODE (node)->parser, parent);
+  TSNode treesit_node = XTS_NODE (node)->node;
+  Lisp_Object parser = XTS_NODE (node)->parser;
+  TSTreeCursor cursor = treesit_cursor_helper (treesit_node, parser);
+  if (ts_tree_cursor_goto_parent (&cursor))
+  {
+    TSNode parent = ts_tree_cursor_current_node (&cursor);
+    return_value = make_treesit_node (parser, parent);
+  }
+  ts_tree_cursor_delete (&cursor);
+  return return_value;
 }
 
 DEFUN ("treesit-node-child",
@@ -1990,14 +2039,12 @@ Note that this function returns an immediate child, not 
the smallest
   if (NILP (node))
     return Qnil;
   treesit_check_node (node);
-  treesit_check_positive_integer (pos);
 
   struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer);
   ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
   ptrdiff_t byte_pos = buf_charpos_to_bytepos (buf, XFIXNUM (pos));
 
-  if (byte_pos < BUF_BEGV_BYTE (buf) || byte_pos > BUF_ZV_BYTE (buf))
-    xsignal1 (Qargs_out_of_range, pos);
+  treesit_check_position (pos, buf);
 
   treesit_initialize ();
 
@@ -2028,19 +2075,14 @@ If NODE is nil, return nil.  */)
 {
   if (NILP (node)) return Qnil;
   treesit_check_node (node);
-  CHECK_INTEGER (beg);
-  CHECK_INTEGER (end);
 
   struct buffer *buf = XBUFFER (XTS_PARSER (XTS_NODE (node)->parser)->buffer);
   ptrdiff_t visible_beg = XTS_PARSER (XTS_NODE (node)->parser)->visible_beg;
   ptrdiff_t byte_beg = buf_charpos_to_bytepos (buf, XFIXNUM (beg));
   ptrdiff_t byte_end = buf_charpos_to_bytepos (buf, XFIXNUM (end));
 
-  /* Checks for BUFFER_BEG <= BEG <= END <= BUFFER_END.  */
-  if (!(BUF_BEGV_BYTE (buf) <= byte_beg
-       && byte_beg <= byte_end
-       && byte_end <= BUF_ZV_BYTE (buf)))
-    xsignal2 (Qargs_out_of_range, beg, end);
+  treesit_check_position (beg, buf);
+  treesit_check_position (end, buf);
 
   treesit_initialize ();
 
@@ -2426,21 +2468,24 @@ the query.  */)
   (Lisp_Object node, Lisp_Object query,
    Lisp_Object beg, Lisp_Object end, Lisp_Object node_only)
 {
-  if (!NILP (beg))
-    CHECK_INTEGER (beg);
-  if (!NILP (end))
-    CHECK_INTEGER (end);
-
   if (!(TS_COMPILED_QUERY_P (query)
        || CONSP (query) || STRINGP (query)))
     wrong_type_argument (Qtreesit_query_p, query);
 
+  treesit_initialize ();
+
   /* Resolve NODE into an actual node.  */
   Lisp_Object lisp_node;
   if (TS_NODEP (node))
-    lisp_node = node;
+    {
+      treesit_check_node (node); /* Check if up-to-date.  */
+      lisp_node = node;
+    }
   else if (TS_PARSERP (node))
-    lisp_node = Ftreesit_parser_root_node (node);
+    {
+      treesit_check_parser (node); /* Check if deleted.  */
+      lisp_node = Ftreesit_parser_root_node (node);
+    }
   else if (SYMBOLP (node))
     {
       Lisp_Object parser
@@ -2452,8 +2497,6 @@ the query.  */)
              list4 (Qor, Qtreesit_node_p, Qtreesit_parser_p, Qsymbolp),
              node);
 
-  treesit_initialize ();
-
   /* Extract C values from Lisp objects.  */
   TSNode treesit_node
     = XTS_NODE (lisp_node)->node;
@@ -2464,6 +2507,13 @@ the query.  */)
   const TSLanguage *lang
     = ts_parser_language (XTS_PARSER (lisp_parser)->parser);
 
+  /* Check BEG and END.  */
+  struct buffer *buf = XBUFFER (XTS_PARSER (lisp_parser)->buffer);
+  if (!NILP (beg))
+    treesit_check_position (beg, buf);
+  if (!NILP (end))
+    treesit_check_position (end, buf);
+
   /* Initialize query objects.  At the end of this block, we should
      have a working TSQuery and a TSQueryCursor.  */
   TSQuery *treesit_query;
@@ -2507,14 +2557,15 @@ the query.  */)
   /* Set query range.  */
   if (!NILP (beg) && !NILP (end))
     {
-      EMACS_INT beg_byte = XFIXNUM (beg);
-      EMACS_INT end_byte = XFIXNUM (end);
+      ptrdiff_t beg_byte = CHAR_TO_BYTE (XFIXNUM (beg));
+      ptrdiff_t end_byte = CHAR_TO_BYTE (XFIXNUM (end));
       /* We never let tree-sitter run on buffers too large, so these
         assertion should never hit.  */
       eassert (beg_byte - visible_beg <= UINT32_MAX);
       eassert (end_byte - visible_beg <= UINT32_MAX);
-      ts_query_cursor_set_byte_range (cursor, (uint32_t) beg_byte - 
visible_beg,
-                                     (uint32_t) end_byte - visible_beg);
+      ts_query_cursor_set_byte_range (cursor,
+                                     (uint32_t) (beg_byte - visible_beg),
+                                     (uint32_t) (end_byte - visible_beg));
     }
 
   /* Execute query.  */
@@ -2580,63 +2631,210 @@ the query.  */)
 
 /*** Navigation */
 
-/* Return the next/previous named/unnamed sibling of NODE.  FORWARD
-   controls the direction and NAMED controls the nameness.  */
-static TSNode
-treesit_traverse_sibling_helper (TSNode node, bool forward, bool named)
+static inline void
+treesit_assume_true (bool val)
+{
+  eassert (val == true);
+}
+
+/* Create a TSTreeCursor pointing at NODE.  PARSER is the lisp parser
+   that produced NODE.
+
+   The reason we need this instead of simply using ts_tree_cursor_new
+   is that we have to create the cursor on the root node and traverse
+   down to NODE, in order to record the correct stack of parent nodes.
+   Otherwise going to sibling or parent of NODE wouldn't work.
+
+   (Wow perfect filling.)  */
+static TSTreeCursor
+treesit_cursor_helper (TSNode node, Lisp_Object parser)
+{
+  uint32_t end_pos = ts_node_end_byte (node);
+  TSNode root = ts_tree_root_node (XTS_PARSER (parser)->tree);
+  TSTreeCursor cursor = ts_tree_cursor_new (root);
+  TSNode cursor_node = ts_tree_cursor_current_node (&cursor);
+  /* This is like treesit-node-at.  We go down from the root node,
+     either to first child or next sibling, repeatedly, and finally
+     arrive at NODE.  */
+  while (!ts_node_eq (node, cursor_node))
+    {
+      treesit_assume_true (ts_tree_cursor_goto_first_child (&cursor));
+      cursor_node = ts_tree_cursor_current_node (&cursor);
+      /* ts_tree_cursor_goto_first_child_for_byte is not reliable, so
+        we just go through each sibling.  */
+      while (ts_node_is_missing (cursor_node)
+            || ts_node_end_byte (cursor_node) < end_pos)
+       {
+         /* A "missing" node has zero width, so it's possible that
+            its end = NODE.end but it's not NODE, so we skip them.
+            But we need to make sure this missing node is not the
+            node we are looking for before skipping it.  */
+         if (ts_node_is_missing (cursor_node)
+             && ts_node_eq (node, cursor_node))
+           return cursor;
+         treesit_assume_true (ts_tree_cursor_goto_next_sibling (&cursor));
+         cursor_node = ts_tree_cursor_current_node (&cursor);
+       }
+      /* Right now CURSOR.end >= NODE.end.  But what if CURSOR.end =
+        NODE.end, and there are missing nodes after CURSOR, and the
+        missing node after CURSOR is the NODE we are looking for??
+        Well, create a probe and look ahead.  (This is tested by
+        treesit-cursor-helper-with-missing-node.)  */
+      TSTreeCursor probe = ts_tree_cursor_copy (&cursor);
+      TSNode probe_node;
+      while (ts_tree_cursor_goto_next_sibling (&probe))
+       {
+         probe_node = ts_tree_cursor_current_node (&probe);
+         if (!ts_node_is_missing (probe_node))
+           break;
+         if (ts_node_eq (probe_node, node))
+           {
+             ts_tree_cursor_delete (&cursor);
+             return probe;
+           }
+       }
+      ts_tree_cursor_delete (&probe);
+    }
+  return cursor;
+}
+
+/* Move CURSOR to the next/previous sibling.  FORWARD controls the
+   direction.  NAMED controls the namedness.  If there is a valid
+   sibling, move CURSOR to it and return true, otherwise return false.
+   When false is returned, CURSOR points to a sibling node of the node
+   we started at, but exactly which is undefined.  */
+static bool
+treesit_traverse_sibling_helper (TSTreeCursor *cursor,
+                                bool forward, bool named)
 {
   if (forward)
     {
-      if (named)
-       return ts_node_next_named_sibling (node);
-      else
-       return ts_node_next_sibling (node);
+      if (!named)
+       return ts_tree_cursor_goto_next_sibling (cursor);
+      /* Else named...  */
+      while (ts_tree_cursor_goto_next_sibling (cursor))
+       {
+         if (ts_node_is_named (ts_tree_cursor_current_node (cursor)))
+           return true;
+       }
+      return false;
     }
-  else
+  else /* Backward.  */
     {
-      if (named)
-       return ts_node_prev_named_sibling (node);
-      else
-       return ts_node_prev_sibling (node);
+      /* Go to first child and go through each sibling, until we find
+        the one just before the starting node.  */
+      TSNode start = ts_tree_cursor_current_node (cursor);
+      if (!ts_tree_cursor_goto_parent (cursor))
+       return false;
+      treesit_assume_true (ts_tree_cursor_goto_first_child (cursor));
+
+      /* Now CURSOR is at the first child.  If we started at the first
+        child, then there is no further siblings.  */
+      TSNode first_child = ts_tree_cursor_current_node (cursor);
+      if (ts_node_eq (first_child, start))
+       return false;
+
+      /* PROBE is always DELTA siblings ahead of CURSOR. */
+      TSTreeCursor probe = ts_tree_cursor_copy (cursor);
+      /* This is position of PROBE minus position of CURSOR.  */
+      ptrdiff_t delta = 0;
+      TSNode probe_node;
+      TSNode cursor_node;
+      while (ts_tree_cursor_goto_next_sibling (&probe))
+       {
+         /* Move PROBE forward, if it equals to the starting node,
+            CURSOR points to the node we want (prev valid sibling of
+            the starting node).  */
+         delta++;
+         probe_node = ts_tree_cursor_current_node (&probe);
+
+         /* PROBE matched, depending on NAMED, return true/false.  */
+         if (ts_node_eq (probe_node, start))
+           {
+             ts_tree_cursor_delete (&probe);
+             cursor_node = ts_tree_cursor_current_node (cursor);
+             ts_tree_cursor_delete (&probe);
+             return (!named || (named && ts_node_is_named (cursor_node)));
+           }
+
+         /* PROBE didn't match, move CURSOR forward to PROBE's
+            position, but if we are looking for named nodes, only
+            move CURSOR to PROBE if PROBE is at a named node.  */
+         if (!named || (named && ts_node_is_named (probe_node)))
+           for (; delta > 0; delta--)
+             treesit_assume_true (ts_tree_cursor_goto_next_sibling (cursor));
+       }
+      ts_tree_cursor_delete (&probe);
+      return false;
     }
 }
 
-/* Return the first/last named/unnamed child of NODE.  FORWARD controls
-   the direction and NAMED controls the nameness.  */
-static TSNode
-treesit_traverse_child_helper (TSNode node, bool forward, bool named)
+/* Move CURSOR to the first/last child.  FORWARD controls the
+   direction.  NAMED controls the namedness.  If there is a valid
+   child, move CURSOR to it and return true, otherwise don't move
+   CURSOR and return false.  */
+static bool
+treesit_traverse_child_helper (TSTreeCursor *cursor,
+                              bool forward, bool named)
 {
   if (forward)
     {
-      if (named)
-       return ts_node_named_child (node, 0);
+      if (!named)
+       return ts_tree_cursor_goto_first_child (cursor);
       else
-       return ts_node_child (node, 0);
-    }
-  else
-    {
-      if (named)
        {
-         uint32_t count = ts_node_named_child_count (node);
-         uint32_t idx = count == 0 ? 0 : count - 1;
-         return ts_node_named_child (node, idx);
+         if (!ts_tree_cursor_goto_first_child (cursor))
+           return false;
+         /* After this point, if you return false, make sure to go
+            back to parent.  */
+         TSNode first_child = ts_tree_cursor_current_node (cursor);
+         if (ts_node_is_named (first_child))
+           return true;
+
+         if (treesit_traverse_sibling_helper (cursor, true, true))
+           return true;
+         else
+           {
+             treesit_assume_true (ts_tree_cursor_goto_parent (cursor));
+             return false;
+           }
        }
+    }
+  else /* Backward.  */
+    {
+      if (!ts_tree_cursor_goto_first_child (cursor))
+       return false;
+      /* After this point, if you return false, make sure to go
+        back to parent.  */
+
+      /* First go to the last child.  */
+      while (ts_tree_cursor_goto_next_sibling (cursor));
+
+      if (!named)
+       return true;
+      /* Else named... */
+      if (treesit_traverse_sibling_helper(cursor, false, true))
+       return true;
       else
        {
-         uint32_t count = ts_node_child_count (node);
-         uint32_t idx = count == 0 ? 0 : count - 1;
-         return ts_node_child (node, idx);
+         treesit_assume_true (ts_tree_cursor_goto_parent (cursor));
+         return false;
        }
     }
 }
 
-/* Return true if NODE matches PRED.  PRED can be a string or a
-   function.  This function assumes PRED is either a string or a
-   function.  */
+/* Return true if the node at CURSOR matches PRED.  PRED can be a
+   string or a function.  This function assumes PRED is either a
+   string or a function.  If NAMED is true, also check that the node
+   is named.  */
 static bool
-treesit_traverse_match_predicate (TSNode node, Lisp_Object pred,
-                                 Lisp_Object parser)
+treesit_traverse_match_predicate (TSTreeCursor *cursor, Lisp_Object pred,
+                                 Lisp_Object parser, bool named)
 {
+  TSNode node = ts_tree_cursor_current_node (cursor);
+  if (named && !ts_node_is_named (node))
+    return false;
+
   if (STRINGP (pred))
     {
       const char *type = ts_node_type (node);
@@ -2647,73 +2845,60 @@ treesit_traverse_match_predicate (TSNode node, 
Lisp_Object pred,
       Lisp_Object lisp_node = make_treesit_node (parser, node);
       return !NILP (CALLN (Ffuncall, pred, lisp_node));
     }
-
 }
 
-/* Traverse the parse tree starting from ROOT (but ROOT is not
-   matches against PRED).  PRED can be a function (takes a node and
-   returns nil/non-nil),or a string (treated as regexp matching the
-   node's type, ignores case, must be all single byte characters).  If
-   the node satisfies PRED , terminate, set ROOT to that node, and
-   return true.  If no node satisfies PRED, return FALSE.  PARSER is
-   the parser of ROOT.
+/* Traverse the parse tree starting from CURSOR.  PRED can be a
+   function (takes a node and returns nil/non-nil), or a string
+   (treated as regexp matching the node's type, must be all single
+   byte characters).  If the node satisfies PRED, leave CURSOR on that
+   node and return true.  If no node satisfies PRED, move CURSOR back
+   to starting position and return false.
 
    LIMIT is the number of levels we descend in the tree.  FORWARD
    controls the direction in which we traverse the tree, true means
-   forward, false backward.  If NAMED is true, only traverse named
-   nodes, if false, all nodes.  If SKIP_ROOT is true, don't match
-   ROOT.  */
+   forward, false backward.  If SKIP_ROOT is true, don't match ROOT.
+   */
 static bool
-treesit_search_dfs (TSNode *root, Lisp_Object pred, Lisp_Object parser,
-                   bool named, bool forward, ptrdiff_t limit,
+treesit_search_dfs (TSTreeCursor *cursor,
+                   Lisp_Object pred, Lisp_Object parser,
+                   bool forward, bool named, ptrdiff_t limit,
                    bool skip_root)
 {
-  /* TSTreeCursor doesn't allow us to move backward, so we can't use
-     it.  */
-  TSNode node = *root;
+  if (!skip_root
+      && treesit_traverse_match_predicate (cursor, pred, parser, named))
+    return true;
 
-  if (!skip_root && treesit_traverse_match_predicate (node, pred, parser))
-    {
-      *root = node;
-      return true;
-    }
+  if (limit == 0)
+    return false;
 
-  if (limit <= 0)
+  if (!treesit_traverse_child_helper (cursor, forward, named))
     return false;
-  else
+  /* After this point, if you return false, make sure to go back to
+     parent.  */
+
+  do /* Iterate through each child.  */
     {
-      int count = (named
-                  ? ts_node_named_child_count (node)
-                  : ts_node_child_count (node));
-      for (int offset = 0; offset < count; offset++)
-       {
-         uint32_t idx = forward ? offset : count - offset - 1;
-         TSNode child = (named
-                         ? ts_node_named_child (node, idx)
-                         : ts_node_child (node, idx));
-
-         if (!ts_node_is_null (child)
-             && treesit_search_dfs (&child, pred, parser, named,
-                                    forward, limit - 1, false))
-           {
-             *root = child;
-             return true;
-           }
-       }
-      return false;
+      if (treesit_search_dfs (cursor, pred, parser, forward,
+                             named, limit - 1, false))
+       return true;
     }
+  while (treesit_traverse_sibling_helper (cursor, forward, false));
+
+  /* No match in any child's subtree, go back to starting node.  */
+  treesit_assume_true (ts_tree_cursor_goto_parent (cursor));
+  return false;
 }
 
 /* Go through the whole tree linearly, leaf-first, starting from
    START.  PRED, PARSER, NAMED, FORWARD are the same as in
-   ts_search_subtre.  If UP_ONLY is true, never go to children, only
-   sibling and parents.  */
+   ts_search_subtree.  If a match is found, leave CURSOR at that node,
+   and return true, if no match is found, return false, and CURSOR's
+   position is undefined.  */
 static bool
-treesit_search_forward (TSNode *start, Lisp_Object pred, Lisp_Object parser,
-                       bool named, bool forward)
+treesit_search_forward (TSTreeCursor *cursor,
+                       Lisp_Object pred, Lisp_Object parser,
+                       bool forward, bool named)
 {
-  TSNode node = *start;
-
   /* We don't search for subtree and always search from the leaf
      nodes.  This way repeated call of this function traverses each
      node in the tree once and only once:
@@ -2723,39 +2908,26 @@ treesit_search_forward (TSNode *start, Lisp_Object 
pred, Lisp_Object parser,
   bool initial = true;
   while (true)
     {
-      if (!initial /* We don't match START.  */
-         && treesit_traverse_match_predicate (node, pred, parser))
-       {
-         *start = node;
-         return true;
-       }
+      if (!initial /* We don't match the starting node.  */
+         && treesit_traverse_match_predicate (cursor, pred, parser, named))
+       return true;
       initial = false;
 
-      TSNode next = treesit_traverse_sibling_helper (node, forward, named);
-      while (ts_node_is_null (next))
+      /* Try going to the next sibling, if there is no next sibling,
+        go to parent and try again.  */
+      while (!treesit_traverse_sibling_helper (cursor, forward, named))
        {
          /* There is no next sibling, go to parent.  */
-         node = ts_node_parent (node);
-         if (ts_node_is_null (node))
+         if (!ts_tree_cursor_goto_parent (cursor))
            return false;
 
-         if (treesit_traverse_match_predicate (node, pred, parser))
-           {
-             *start = node;
+         if (treesit_traverse_match_predicate (cursor, pred, parser, named))
              return true;
-           }
-         next = treesit_traverse_sibling_helper (node, forward, named);
        }
       /* We are at the next sibling, deep dive into the first leaf
         node.  */
-      TSNode next_next = treesit_traverse_child_helper (next, forward, named);
-      while (!ts_node_is_null (next_next))
-       {
-         next = next_next;
-         next_next = treesit_traverse_child_helper (next, forward, named);
-       }
-      /* At this point NEXT is a leaf node.  */
-      node = next;
+      while (treesit_traverse_child_helper (cursor, forward, false));
+      /* At this point CURSOR is at a leaf node.  */
     }
 }
 
@@ -2783,7 +2955,7 @@ Return the first matched node, or nil if none matches.  
*/)
   CHECK_SYMBOL (all);
   CHECK_SYMBOL (backward);
 
-  /* We use a default limit to 1000.  See bug#59426 for the
+  /* We use a default limit of 1000.  See bug#59426 for the
      discussion.  */
   ptrdiff_t the_limit = 1000;
   if (!NILP (limit))
@@ -2794,13 +2966,17 @@ Return the first matched node, or nil if none matches.  
*/)
 
   treesit_initialize ();
 
-  TSNode treesit_node = XTS_NODE (node)->node;
   Lisp_Object parser = XTS_NODE (node)->parser;
-  if (treesit_search_dfs (&treesit_node, predicate, parser, NILP (all),
-                         NILP (backward), the_limit, false))
-    return make_treesit_node (parser, treesit_node);
-  else
-    return Qnil;
+  Lisp_Object return_value = Qnil;
+  TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (node)->node, parser);
+  if (treesit_search_dfs (&cursor, predicate, parser, NILP (backward),
+                         NILP (all), the_limit, false))
+    {
+      TSNode node = ts_tree_cursor_current_node (&cursor);
+      return_value = make_treesit_node (parser, node);
+    }
+  ts_tree_cursor_delete (&cursor);
+  return return_value;
 }
 
 DEFUN ("treesit-search-forward",
@@ -2844,13 +3020,17 @@ always traverse leaf nodes first, then upwards.  */)
 
   treesit_initialize ();
 
-  TSNode treesit_start = XTS_NODE (start)->node;
   Lisp_Object parser = XTS_NODE (start)->parser;
-  if (treesit_search_forward (&treesit_start, predicate, parser, NILP (all),
-                             NILP (backward)))
-    return make_treesit_node (parser, treesit_start);
-  else
-    return Qnil;
+  Lisp_Object return_value = Qnil;
+  TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (start)->node, parser);
+  if (treesit_search_forward (&cursor, predicate, parser,
+                             NILP (backward), NILP (all)))
+    {
+      TSNode node = ts_tree_cursor_current_node (&cursor);
+      return_value = make_treesit_node (parser, node);
+    }
+  ts_tree_cursor_delete (&cursor);
+  return return_value;
 }
 
 /* Recursively traverse the tree under CURSOR, and append the result
@@ -2862,13 +3042,12 @@ treesit_build_sparse_tree (TSTreeCursor *cursor, 
Lisp_Object parent,
                           Lisp_Object pred, Lisp_Object process_fn,
                           ptrdiff_t limit, Lisp_Object parser)
 {
-
-  TSNode node = ts_tree_cursor_current_node (cursor);
-  bool match = treesit_traverse_match_predicate (node, pred, parser);
+  bool match = treesit_traverse_match_predicate (cursor, pred, parser, false);
   if (match)
     {
       /* If this node matches pred, add a new node to the parent's
         children list.  */
+      TSNode node = ts_tree_cursor_current_node (cursor);
       Lisp_Object lisp_node = make_treesit_node (parser, node);
       if (!NILP (process_fn))
        lisp_node = CALLN (Ffuncall, process_fn, lisp_node);
@@ -2949,7 +3128,7 @@ a regexp.  */)
   if (!NILP (process_fn))
     CHECK_TYPE (FUNCTIONP (process_fn), Qfunctionp, process_fn);
 
-  /* We use a default limit to 1000.  See bug#59426 for the
+  /* We use a default limit of 1000.  See bug#59426 for the
      discussion.  */
   ptrdiff_t the_limit = 1000;
   if (!NILP (limit))
@@ -2960,11 +3139,12 @@ a regexp.  */)
 
   treesit_initialize ();
 
-  TSTreeCursor cursor = ts_tree_cursor_new (XTS_NODE (root)->node);
   Lisp_Object parser = XTS_NODE (root)->parser;
   Lisp_Object parent = Fcons (Qnil, Qnil);
+  TSTreeCursor cursor = treesit_cursor_helper (XTS_NODE (root)->node, parser);
   treesit_build_sparse_tree (&cursor, parent, predicate, process_fn,
                             the_limit, parser);
+  ts_tree_cursor_delete (&cursor);
   Fsetcdr (parent, Fnreverse (Fcdr (parent)));
   if (NILP (Fcdr (parent)))
     return Qnil;
diff --git a/src/window.c b/src/window.c
index f116b9a9d7..90fa6ac2df 100644
--- a/src/window.c
+++ b/src/window.c
@@ -2639,7 +2639,7 @@ window_list (void)
          Lisp_Object arglist = Qnil;
 
          /* We are visiting windows in canonical order, and add
-            new windows at the front of args[1], which means we
+            new windows at the front of arglist, which means we
             have to reverse this list at the end.  */
          foreach_window (XFRAME (frame), add_window_to_list, &arglist);
          arglist = Fnreverse (arglist);
@@ -7329,6 +7329,14 @@ the return value is nil.  Otherwise the value is t.  */)
            last_selected_window)
        = selected_window;
 
+      /* We may have deleted windows above.  Then again, maybe we
+        haven't: the functions we call to maybe delete windows can
+        decide a window cannot be deleted.  Force recalculation of
+        Vwindow_list next time it is needed, to make sure stale
+        windows with no buffers don't escape into the wild, which
+        will cause crashes elsewhere.  */
+      Vwindow_list = Qnil;
+
       if (NILP (data->focus_frame)
          || (FRAMEP (data->focus_frame)
              && FRAME_LIVE_P (XFRAME (data->focus_frame))))
diff --git a/src/xdisp.c b/src/xdisp.c
index 4e087bc39b..e8df230ef8 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -6281,13 +6281,16 @@ static ptrdiff_t
 string_buffer_position (Lisp_Object string, ptrdiff_t around_charpos)
 {
   const int MAX_DISTANCE = 1000;
+  ptrdiff_t forward_limit = min (around_charpos + MAX_DISTANCE, ZV);
   ptrdiff_t found = string_buffer_position_lim (string, around_charpos,
-                                               around_charpos + MAX_DISTANCE,
-                                               false);
+                                               forward_limit, false);
 
   if (!found)
-    found = string_buffer_position_lim (string, around_charpos,
-                                       around_charpos - MAX_DISTANCE, true);
+    {
+      ptrdiff_t backward_limit = max (around_charpos - MAX_DISTANCE, BEGV);
+      found = string_buffer_position_lim (string, around_charpos,
+                                         backward_limit, true);
+    }
   return found;
 }
 
@@ -17264,7 +17267,6 @@ mark_window_display_accurate_1 (struct window *w, bool 
accurate_p)
 
       BUF_UNCHANGED_MODIFIED (b) = BUF_MODIFF (b);
       BUF_OVERLAY_UNCHANGED_MODIFIED (b) = BUF_OVERLAY_MODIFF (b);
-      BUF_CHARS_UNCHANGED_MODIFIED (b) = BUF_CHARS_MODIFF (b);
       BUF_BEG_UNCHANGED (b) = BUF_GPT (b) - BUF_BEG (b);
       BUF_END_UNCHANGED (b) = BUF_Z (b) - BUF_GPT (b);
 
@@ -19430,6 +19432,13 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
            blank_row (w, row, y);
          goto finish_scroll_bars;
        }
+      else if (minibuf_level >= 1)
+       {
+         /* We could have a message produced by set-minibuffer-message
+            displayed in the mini-window as an overlay, so resize the
+            mini-window if needed.  */
+         resize_mini_window (w, false);
+       }
 
       clear_glyph_matrix (w->desired_matrix);
     }
@@ -19535,7 +19544,7 @@ redisplay_window (Lisp_Object window, bool 
just_this_one_p)
   /* Check whether the buffer to be displayed contains long lines.  */
   if (!NILP (Vlong_line_threshold)
       && !current_buffer->long_line_optimizations_p
-      && (CHARS_MODIFF - CHARS_UNCHANGED_MODIFIED > 8
+      && (CHARS_MODIFF - UNCHANGED_MODIFIED > 8
          || current_buffer->clip_changed))
     {
       ptrdiff_t cur, next, found, max = 0, threshold;
diff --git a/src/xfaces.c b/src/xfaces.c
index f96e538360..0189e61212 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -6013,6 +6013,23 @@ realize_non_ascii_face (struct frame *f, Lisp_Object 
font_object,
 }
 #endif /* HAVE_WINDOW_SYSTEM */
 
+/* Remove the attribute at INDEX from the font object if SYMBOL
+   appears in `font-fallback-ignored-attributes'.  */
+
+static void
+font_maybe_unset_attribute (Lisp_Object font_object,
+                           enum font_property_index index, Lisp_Object symbol)
+{
+  Lisp_Object tail = Vface_font_lax_matched_attributes;
+
+  eassert (CONSP (tail));
+
+  FOR_EACH_TAIL_SAFE (tail)
+    {
+      if (EQ (XCAR (tail), symbol))
+       ASET (font_object, index, Qnil);
+    }
+}
 
 /* Realize the fully-specified face with attributes ATTRS in face
    cache CACHE for ASCII characters.  Do it for GUI frame CACHE->f.
@@ -6070,8 +6087,48 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
            emacs_abort ();
        }
       if (! FONT_OBJECT_P (attrs[LFACE_FONT_INDEX]))
-       attrs[LFACE_FONT_INDEX]
-         = font_load_for_lface (f, attrs, attrs[LFACE_FONT_INDEX]);
+       {
+         Lisp_Object spec = copy_font_spec (attrs[LFACE_FONT_INDEX]);
+
+         /* Maybe unset several values in SPEC, usually the width,
+            slant, and weight.  The best possible values for these
+            attributes are determined in font_find_for_lface, called
+            by font_load_for_lface, when the list of candidate fonts
+            returned by font_list_entities is sorted by font_select_entity
+            (which calls font_sort_entities, which calls font_score).
+            If these attributes are not unset here, the candidate
+            font list returned by font_list_entities only contains
+            fonts that are exact matches for these weight, slant, and
+            width attributes, which could lead to suboptimal or wrong
+            font selection.  (bug#5934) */
+         if (EQ (Vface_font_lax_matched_attributes, Qt))
+           {
+             /* The default case: clear the font attributes that
+                affect its appearance the least, to try to find some
+                font that is close, if not exact, match.  */
+             ASET (spec, FONT_WEIGHT_INDEX, Qnil);
+             ASET (spec, FONT_SLANT_INDEX, Qnil);
+             ASET (spec, FONT_WIDTH_INDEX, Qnil);
+           }
+         else if (!NILP (Vface_font_lax_matched_attributes))
+           {
+             /* Also allow unsetting specific attributes for
+                debugging purposes.  */
+             font_maybe_unset_attribute (spec, FONT_WEIGHT_INDEX, QCweight);
+             font_maybe_unset_attribute (spec, FONT_SLANT_INDEX, QCslant);
+             font_maybe_unset_attribute (spec, FONT_WIDTH_INDEX, QCwidth);
+             font_maybe_unset_attribute (spec, FONT_FAMILY_INDEX, QCfamily);
+             font_maybe_unset_attribute (spec, FONT_FOUNDRY_INDEX, QCfoundry);
+             font_maybe_unset_attribute (spec, FONT_REGISTRY_INDEX, 
QCregistry);
+             font_maybe_unset_attribute (spec, FONT_ADSTYLE_INDEX, QCadstyle);
+             font_maybe_unset_attribute (spec, FONT_SIZE_INDEX, QCsize);
+             font_maybe_unset_attribute (spec, FONT_DPI_INDEX, QCdpi);
+             font_maybe_unset_attribute (spec, FONT_SPACING_INDEX, QCspacing);
+             font_maybe_unset_attribute (spec, FONT_AVGWIDTH_INDEX, 
QCavgwidth);
+           }
+
+         attrs[LFACE_FONT_INDEX] = font_load_for_lface (f, attrs, spec);
+       }
       if (FONT_OBJECT_P (attrs[LFACE_FONT_INDEX]))
        {
          face->font = XFONT_OBJECT (attrs[LFACE_FONT_INDEX]);
@@ -7359,6 +7416,35 @@ Lisp programs that change the value of this variable 
should also
 clear the face cache, see `clear-face-cache'.  */);
   face_near_same_color_threshold = 30000;
 
+  DEFVAR_LISP ("face-font-lax-matched-attributes",
+              Vface_font_lax_matched_attributes,
+              doc: /* Whether to match some face attributes in lax manner when 
realizing faces.
+
+If non-nil, some font-related face attributes will be matched in a lax
+manner when looking for candidate fonts.
+If the value is t, the default, the search for fonts will not insist
+on exact match for 3 font attributes: weight, width, and slant.
+Instead, it will examine the available fonts with various values of
+these attributes, and select the font that is the closest possible
+match.  (If an exact match is available, it will still be selected,
+as that is the closest match.)  For example, looking for a semi-bold
+font might select a bold or a medium-weight font if no semi-bold font
+matching other attributes can be found.  This is especially important
+when the `default' face specifies unusual values for one or more of
+these 3 attributes, which other installed fonts don't support.
+
+The value can also be a list of font-related face attribute symbols;
+see `set-face-attribute' for the full list of attributes.  Then the
+corresponding face attributes will be treated as "soft" constraints
+in the manner described above, instead of the default 3 attributes.
+
+If the value is nil, candidate fonts might be rejected if the don't
+have exactly the same values of attributes as the face requests.
+
+This variable exists for debugging of the font-selection process,
+and we advise not to change it otherwise.  */);
+  Vface_font_lax_matched_attributes = Qt;
+
 #ifdef HAVE_WINDOW_SYSTEM
   defsubr (&Sbitmap_spec_p);
   defsubr (&Sx_list_fonts);
diff --git a/src/xfns.c b/src/xfns.c
index df805d66db..668f711bdb 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -43,7 +43,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #ifdef USE_XCB
 #include <xcb/xcb.h>
 #include <xcb/xproto.h>
-#include <xcb/xcb_aux.h>
 #endif
 
 #include "bitmaps/gray.xbm"
@@ -1368,7 +1367,7 @@ x_set_mouse_color (struct frame *f, Lisp_Object arg, 
Lisp_Object oldval)
         XCreateFontCursor is not a request that waits for a reply,
         and as such can return IDs that will not actually be used by
         the server.  */
-      x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f));
+      x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0);
 
       /* Free any successfully created cursors.  */
       for (i = 0; i < mouse_cursor_max; i++)
@@ -2643,12 +2642,18 @@ append_wm_protocols (struct x_display_info *dpyinfo,
   if (existing)
     XFree (existing);
 
-  if (!found_wm_ping)
-    protos[num_protos++] = dpyinfo->Xatom_net_wm_ping;
+  if (!dpyinfo->untrusted)
+    {
+      /* Untrusted clients cannot use these protocols which require
+        communicating with the window manager.  */
+
+      if (!found_wm_ping)
+       protos[num_protos++] = dpyinfo->Xatom_net_wm_ping;
 #if !defined HAVE_GTK3 && defined HAVE_XSYNC
-  if (!found_wm_sync_request && dpyinfo->xsync_supported_p)
-    protos[num_protos++] = dpyinfo->Xatom_net_wm_sync_request;
+      if (!found_wm_sync_request && dpyinfo->xsync_supported_p)
+       protos[num_protos++] = dpyinfo->Xatom_net_wm_sync_request;
 #endif
+    }
 
   if (num_protos)
     XChangeProperty (dpyinfo->display,
@@ -5723,13 +5728,13 @@ x_get_net_workarea (struct x_display_info *dpyinfo, 
XRectangle *rect)
     = xcb_get_property (dpyinfo->xcb_connection, 0,
                        (xcb_window_t) dpyinfo->root_window,
                        (xcb_atom_t) dpyinfo->Xatom_net_current_desktop,
-                       XCB_ATOM_CARDINAL, 0, 1);
+                       XA_CARDINAL, 0, 1);
 
   workarea_cookie
     = xcb_get_property (dpyinfo->xcb_connection, 0,
                        (xcb_window_t) dpyinfo->root_window,
                        (xcb_atom_t) dpyinfo->Xatom_net_workarea,
-                       XCB_ATOM_CARDINAL, 0, UINT32_MAX);
+                       XA_CARDINAL, 0, UINT32_MAX);
 
   reply = xcb_get_property_reply (dpyinfo->xcb_connection,
                                  current_desktop_cookie, &error);
@@ -5740,7 +5745,7 @@ x_get_net_workarea (struct x_display_info *dpyinfo, 
XRectangle *rect)
   else
     {
       if (xcb_get_property_value_length (reply) != 4
-         || reply->type != XCB_ATOM_CARDINAL || reply->format != 32)
+         || reply->type != XA_CARDINAL || reply->format != 32)
        rc = false;
       else
        current_workspace = *(uint32_t *) xcb_get_property_value (reply);
@@ -5755,7 +5760,7 @@ x_get_net_workarea (struct x_display_info *dpyinfo, 
XRectangle *rect)
     free (error), rc = false;
   else
     {
-      if (rc && reply->type == XCB_ATOM_CARDINAL && reply->format == 32
+      if (rc && reply->type == XA_CARDINAL && reply->format == 32
          && (xcb_get_property_value_length (reply) / sizeof (uint32_t)
              >= current_workspace + 4))
        {
@@ -7377,20 +7382,6 @@ If TERMINAL is omitted or nil, that stands for the 
selected frame's display.  */
   return Qnil;
 }
 
-/* Wait for responses to all X commands issued so far for frame F.  */
-
-void
-x_sync (struct frame *f)
-{
-  block_input ();
-#ifndef USE_XCB
-  XSync (FRAME_X_DISPLAY (f), False);
-#else
-  xcb_aux_sync (FRAME_DISPLAY_INFO (f)->xcb_connection);
-#endif
-  unblock_input ();
-}
-
 
 /***********************************************************************
                            Window properties
diff --git a/src/xselect.c b/src/xselect.c
index 121b17df1b..05548be311 100644
--- a/src/xselect.c
+++ b/src/xselect.c
@@ -16,7 +16,6 @@ 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/>.  */
 
-
 /* Rewritten by jwz */
 
 #include <config.h>
@@ -44,7 +43,7 @@ struct prop_location;
 struct selection_data;
 
 static void x_decline_selection_request (struct selection_input_event *);
-static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, bool,
+static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom,
                                 struct x_display_info *, bool);
 static bool waiting_for_other_props_on_window (Display *, Window);
 static struct prop_location *expect_property_change (Display *, Window,
@@ -461,7 +460,7 @@ x_decline_selection_request (struct selection_input_event 
*event)
   /* The reason for the error may be that the receiver has
      died in the meantime.  Handle that case.  */
   block_input ();
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, reply->requestor,
              False, 0, &reply_base);
   x_stop_ignoring_errors (dpyinfo);
@@ -524,6 +523,9 @@ struct transfer
   /* The atimer for the timeout.  */
   struct atimer *timeout;
 
+  /* The selection serial.  */
+  unsigned int serial;
+
   /* Flags.  */
   int flags;
 };
@@ -544,8 +546,8 @@ struct x_selection_request
   /* Linked list of the above (in support of MULTIPLE targets).  */
   struct selection_data *converted_selections;
 
-  /* "Data" to send a requestor for a failed MULTIPLE subtarget.  */
-  Atom conversion_fail_tag;
+  /* The serial used to handle X errors.  */
+  unsigned int serial;
 
   /* Whether or not conversion was successful.  */
   bool converted;
@@ -561,6 +563,10 @@ struct x_selection_request *selection_request_stack;
 
 struct transfer outstanding_transfers;
 
+/* A counter for selection serials.  */
+
+static unsigned int selection_serial;
+
 
 
 struct prop_location
@@ -608,7 +614,6 @@ x_push_current_selection_request (struct 
selection_input_event *se,
   frame->request = se;
   frame->dpyinfo = dpyinfo;
   frame->converted_selections = NULL;
-  frame->conversion_fail_tag = None;
 
   selection_request_stack = frame;
 }
@@ -798,7 +803,7 @@ x_cancel_selection_transfer (struct transfer *transfer)
       /* Ignore errors generated by the change window request in case
         the window has gone away.  */
       block_input ();
-      x_ignore_errors_for_next_request (transfer->dpyinfo);
+      x_ignore_errors_for_next_request (transfer->dpyinfo, 0);
       XSelectInput (transfer->dpyinfo->display,
                    transfer->requestor, NoEventMask);
       x_stop_ignoring_errors (transfer->dpyinfo);
@@ -839,10 +844,6 @@ x_start_selection_transfer (struct x_display_info 
*dpyinfo, Window requestor,
   secs = timeout / 1000;
   nsecs = (timeout % 1000) * 1000000;
 
-  if ((Atom *) data->data
-      == &selection_request_stack->conversion_fail_tag)
-    return;
-
   transfer = xzalloc (sizeof *transfer);
   transfer->requestor = requestor;
   transfer->dpyinfo = dpyinfo;
@@ -894,12 +895,23 @@ x_start_selection_transfer (struct x_display_info 
*dpyinfo, Window requestor,
       transfer->next->last = transfer;
       transfer->last->next = transfer;
 
+      /* Find a valid (non-zero) serial for the selection transfer.
+        Any asynchronously trapped errors will then cause the
+        selection transfer to be cancelled.  */
+      transfer->serial = (++selection_serial
+                         ? selection_serial
+                         : ++selection_serial);
+
       /* Now, write the INCR property to begin incremental selection
         transfer.  offset is currently 0.  */
 
       data_size = selection_data_size (&transfer->data);
 
-      x_ignore_errors_for_next_request (dpyinfo);
+      /* Set SELECTED_EVENTS before the actual XSelectInput
+        request.  */
+      transfer->flags |= SELECTED_EVENTS;
+
+      x_ignore_errors_for_next_request (dpyinfo, transfer->serial);
       XChangeProperty (dpyinfo->display, requestor,
                       transfer->data.property,
                       dpyinfo->Xatom_INCR, 32, PropModeReplace,
@@ -912,7 +924,6 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, 
Window requestor,
          manager) asks Emacs for selection data, things will subtly go
          wrong.  */
       XSelectInput (dpyinfo->display, requestor, PropertyChangeMask);
-      transfer->flags |= SELECTED_EVENTS;
       x_stop_ignoring_errors (dpyinfo);
     }
   else
@@ -926,7 +937,7 @@ x_start_selection_transfer (struct x_display_info *dpyinfo, 
Window requestor,
              " %zu elements directly to requestor window",
              remaining);
 
-      x_ignore_errors_for_next_request (dpyinfo);
+      x_ignore_errors_for_next_request (dpyinfo, 0);
       XChangeProperty (dpyinfo->display, requestor,
                       transfer->data.property,
                       transfer->data.type,
@@ -960,7 +971,7 @@ x_continue_selection_transfer (struct transfer *transfer)
         signal EOF and remove the transfer.  */
       TRACE0 (" x_continue_selection_transfer: writing 0 items to"
              " indicate EOF");
-      x_ignore_errors_for_next_request (transfer->dpyinfo);
+      x_ignore_errors_for_next_request (transfer->dpyinfo, 0);
       XChangeProperty (transfer->dpyinfo->display,
                       transfer->requestor,
                       transfer->data.property,
@@ -979,7 +990,10 @@ x_continue_selection_transfer (struct transfer *transfer)
              "; current offset is %zu", remaining, transfer->offset);
       eassert (remaining <= INT_MAX);
 
-      x_ignore_errors_for_next_request (transfer->dpyinfo);
+      transfer->offset += remaining;
+
+      x_ignore_errors_for_next_request (transfer->dpyinfo,
+                                       transfer->serial);
       XChangeProperty (transfer->dpyinfo->display,
                       transfer->requestor,
                       transfer->data.property,
@@ -988,7 +1002,6 @@ x_continue_selection_transfer (struct transfer *transfer)
                       PropModeReplace, xdata,
                       remaining);
       x_stop_ignoring_errors (transfer->dpyinfo);
-      transfer->offset += remaining;
     }
 }
 
@@ -1008,6 +1021,40 @@ x_remove_selection_transfers (struct x_display_info 
*dpyinfo)
     }
 }
 
+/* Handle an X error generated trying to write to a window.  SERIAL
+   identifies the outstanding incremental selection transfer, which is
+   immediately removed.  */
+
+void
+x_handle_selection_error (unsigned int serial, XErrorEvent *error)
+{
+  struct transfer *next, *last;
+
+  if (error->error_code != BadWindow)
+    /* The error was not caused by the window going away.  As such,
+       Emacs must deselect for PropertyChangeMask from the requestor
+       window, which isn't safe here.  Return and wait for the timeout
+       to run.  */
+    return;
+
+  next = outstanding_transfers.next;
+  while (next != &outstanding_transfers)
+    {
+      last = next;
+      next = next->next;
+
+      if (last->serial == serial)
+       {
+         /* Clear SELECTED_EVENTS, so x_cancel_selection_transfer
+            will not make X requests.  That is unsafe inside an error
+            handler, and unnecessary because the window has already
+            gone.  */
+         last->flags &= ~SELECTED_EVENTS;
+         x_cancel_selection_transfer (last);
+       }
+    }
+}
+
 /* Send the reply to a selection request event EVENT.  */
 
 static void
@@ -1042,7 +1089,7 @@ x_reply_selection_request (struct selection_input_event 
*event,
 
   /* Send the SelectionNotify event to the requestor, telling it that
      the property data has arrived.  */
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, SELECTION_EVENT_REQUESTOR (event),
              False, NoEventMask, &message);
   x_stop_ignoring_errors (dpyinfo);
@@ -1135,7 +1182,9 @@ x_handle_selection_request (struct selection_input_event 
*event)
       ptrdiff_t j, nselections;
       struct selection_data cs;
 
-      if (property == None) goto DONE;
+      if (property == None)
+       goto DONE;
+
       multprop
        = x_get_window_property_as_lisp_data (dpyinfo, requestor, property,
                                              QMULTIPLE, selection, true);
@@ -1147,17 +1196,17 @@ x_handle_selection_request (struct 
selection_input_event *event)
       /* Perform conversions.  This can signal.  */
       for (j = 0; j < nselections; j++)
        {
-         Lisp_Object subtarget = AREF (multprop, 2*j);
+         Lisp_Object subtarget = AREF (multprop, 2 * j);
          Atom subproperty = symbol_to_x_atom (dpyinfo,
                                               AREF (multprop, 2*j+1));
          bool subsuccess = false;
 
          if (subproperty != None)
            subsuccess = x_convert_selection (selection_symbol, subtarget,
-                                             subproperty, true, dpyinfo,
+                                             subproperty, dpyinfo,
                                              use_alternate);
          if (!subsuccess)
-           ASET (multprop, 2*j+1, Qnil);
+           ASET (multprop, 2 * j + 1, Qnil);
        }
 
       /* Save conversion results */
@@ -1183,8 +1232,7 @@ x_handle_selection_request (struct selection_input_event 
*event)
 
       success = x_convert_selection (selection_symbol,
                                     target_symbol, property,
-                                    false, dpyinfo,
-                                    use_alternate);
+                                    dpyinfo, use_alternate);
     }
 
  DONE:
@@ -1212,15 +1260,13 @@ x_handle_selection_request (struct 
selection_input_event *event)
 
 /* Perform the requested selection conversion, and write the data to
    the converted_selections linked list, where it can be accessed by
-   x_reply_selection_request.  If FOR_MULTIPLE, write out
-   the data even if conversion fails, using conversion_fail_tag.
+   x_reply_selection_request.
 
    Return true if successful.  */
 
 static bool
-x_convert_selection (Lisp_Object selection_symbol,
-                    Lisp_Object target_symbol, Atom property,
-                    bool for_multiple, struct x_display_info *dpyinfo,
+x_convert_selection (Lisp_Object selection_symbol, Lisp_Object target_symbol,
+                    Atom property, struct x_display_info *dpyinfo,
                     bool use_alternate)
 {
   Lisp_Object lisp_selection;
@@ -1236,23 +1282,7 @@ x_convert_selection (Lisp_Object selection_symbol,
   /* A nil return value means we can't perform the conversion.  */
   if (NILP (lisp_selection)
       || (CONSP (lisp_selection) && NILP (XCDR (lisp_selection))))
-    {
-      if (for_multiple)
-       {
-         cs = xmalloc (sizeof *cs);
-         cs->data = ((unsigned char *)
-                     &selection_request_stack->conversion_fail_tag);
-         cs->size = 1;
-         cs->string = Qnil;
-         cs->format = 32;
-         cs->type = XA_ATOM;
-         cs->property = property;
-         cs->next = frame->converted_selections;
-         frame->converted_selections = cs;
-       }
-
-      return false;
-    }
+    return false;
 
   /* Otherwise, record the converted selection to binary.  */
   cs = xmalloc (sizeof *cs);
diff --git a/src/xterm.c b/src/xterm.c
index d57830163c..a1acfa8074 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -26,6 +26,22 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
    contains subroutines comprising the redisplay interface, setting up
    scroll bars and widgets, and handling input.
 
+   X WINDOW SYSTEM
+
+   The X Window System is a windowing system for bitmap graphics
+   displays which originated at MIT in 1984.  Version 11, which is
+   currently supported by Emacs, first appeared in September 1987.
+
+   X has a long history and has been developed by many different
+   organizations over the years; at present, it is being primarily
+   developed by the X.Org Foundation.  It is the main window system
+   that Emacs is developed and tested against, and X version 10 was
+   the first window system that Emacs was ported to.  As a consequence
+   of its age and wide availability, X contains many idiosyncrasies,
+   but that has not prevented it from becoming the dominant free
+   window system, and the platform of reference for all GUI code in
+   Emacs.
+
    Some of what is explained below also applies to the other window
    systems that Emacs supports, to varying degrees.  YMMV.
 
@@ -555,7 +571,56 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
   drop happening with the primary selection and synthetic button
   events (see `x_dnd_do_unsupported_drop').  That function implements
   the OffiX drag-and-drop protocol by default.  See
-  `x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details.  */
+  `x-dnd-handle-unsupported-drop' in `x-dnd.el' for more details.
+
+  DISPLAY ERROR HANDLING
+
+  While error handling under X was originally designed solely as a
+  mechanism for the X server to report fatal errors to clients, most
+  clients (including Emacs) have adopted a system of "error traps" to
+  handle or discard these errors as they arrive.  Discarding errors is
+  usually necessary when Emacs performs an X request that might fail:
+  for example, sending a message to a window that may no longer exist,
+  or might not exist at all.  Handling errors is then necessary when
+  the detailed error must be reported to another piece of code: for
+  example, as a Lisp error.
+
+  It is not acceptable for Emacs to crash when it is sent invalid data
+  by another client, or by Lisp.  As a result, errors must be caught
+  around Xlib functions generating requests containing resource
+  identifiers that could potentially be invalid, such as window or
+  atom identifiers provided in a client message from another program,
+  or a child window ID obtained through XTranslateCoordinates that may
+  refer to a window that has been deleted in the meantime.
+
+  There are two sets of functions used to perform this "error
+  trapping".  Which one should be used depends on what kind of
+  processing must be done on the error.  The first consists of the
+  functions `x_ignore_errors_for_next_request' and
+  `x_stop_ignoring_errors', which ignore errors generated by requests
+  made in between a call to the first function and a corresponding
+  call to the second.  They should be used for simple asynchronous
+  requests that do not require a reply from the X server: using them
+  instead of the second set improves performance, as they simply
+  record a range of request serials to ignore errors from, instead of
+  synchronizing with the X server to handle errors.
+
+  The second set consists of the following functions:
+
+    - x_catch_errors_with_handler
+    - x_catch_errors
+    - x_uncatch_errors_after_check
+    - x_uncatch_errors
+    - x_check_errors
+    - x_had_errors_p
+    - 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
+  being made do not require roundtrips to the X server, and obtaining
+  the details of any error generated is unecessary, as
+  `x_uncatch_errors' will always synchronize with the X server, which
+  is a potentially slow operation.  */
 
 #include <config.h>
 #include <stdlib.h>
@@ -574,7 +639,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #ifdef USE_XCB
 #include <xcb/xproto.h>
 #include <xcb/xcb.h>
-#include <xcb/xcb_aux.h>
 #endif
 
 /* If we have Xfixes extension, use it for pointer blanking.  */
@@ -2523,7 +2587,7 @@ xm_send_drop_message (struct x_display_info *dpyinfo, 
Window source,
   *((uint32_t *) &msg.xclient.data.b[12]) = dmsg->index_atom;
   *((uint32_t *) &msg.xclient.data.b[16]) = dmsg->source_window;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -2550,7 +2614,7 @@ xm_send_top_level_enter_message (struct x_display_info 
*dpyinfo, Window source,
   msg.xclient.data.b[18] = 0;
   msg.xclient.data.b[19] = 0;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -2581,7 +2645,7 @@ xm_send_drag_motion_message (struct x_display_info 
*dpyinfo, Window source,
   msg.xclient.data.b[18] = 0;
   msg.xclient.data.b[19] = 0;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -2640,7 +2704,7 @@ xm_send_top_level_leave_message (struct x_display_info 
*dpyinfo, Window source,
   msg.xclient.data.b[18] = 0;
   msg.xclient.data.b[19] = 0;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -2935,7 +2999,7 @@ x_dnd_free_toplevels (bool display_alive)
       if (n_windows)
        {
          eassume (dpyinfo);
-         x_ignore_errors_for_next_request (dpyinfo);
+         x_ignore_errors_for_next_request (dpyinfo, 0);
 
          for (i = 0; i < n_windows; ++i)
            {
@@ -3072,7 +3136,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
                                     0, 0);
       get_property_cookies[i]
        = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) 
toplevels[i],
-                           (xcb_atom_t) dpyinfo->Xatom_wm_state, XCB_ATOM_ANY,
+                           (xcb_atom_t) dpyinfo->Xatom_wm_state, 0,
                            0, 2);
       xm_property_cookies[i]
        = xcb_get_property (dpyinfo->xcb_connection, 0, (xcb_window_t) 
toplevels[i],
@@ -3083,7 +3147,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
        = xcb_get_property (dpyinfo->xcb_connection, 0,
                            (xcb_window_t) toplevels[i],
                            (xcb_atom_t) dpyinfo->Xatom_net_frame_extents,
-                           XCB_ATOM_CARDINAL, 0, 4);
+                           XA_CARDINAL, 0, 4);
       get_geometry_cookies[i]
        = xcb_get_geometry (dpyinfo->xcb_connection, (xcb_window_t) 
toplevels[i]);
 
@@ -3211,7 +3275,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
        {
          if (xcb_get_property_value_length (extent_property_reply) == 16
              && extent_property_reply->format == 32
-             && extent_property_reply->type == XCB_ATOM_CARDINAL)
+             && extent_property_reply->type == XA_CARDINAL)
            {
              fextents = xcb_get_property_value (extent_property_reply);
              frame_extents[0] = fextents[0];
@@ -3305,7 +3369,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
 
          if (dpyinfo->xshape_supported_p)
            {
-             x_ignore_errors_for_next_request (dpyinfo);
+             x_ignore_errors_for_next_request (dpyinfo, 0);
              XShapeSelectInput (dpyinfo->display,
                                 toplevels[i],
                                 ShapeNotifyMask);
@@ -3470,7 +3534,7 @@ x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
            }
 #endif
 
-         x_ignore_errors_for_next_request (dpyinfo);
+         x_ignore_errors_for_next_request (dpyinfo, 0);
          XSelectInput (dpyinfo->display, toplevels[i],
                        (attrs.your_event_mask
                         | StructureNotifyMask
@@ -3585,13 +3649,13 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, 
Window wdesc,
     xdnd_proxy_cookie = xcb_get_property (dpyinfo->xcb_connection, 0,
                                          (xcb_window_t) wdesc,
                                          (xcb_atom_t) dpyinfo->Xatom_XdndProxy,
-                                         XCB_ATOM_WINDOW, 0, 1);
+                                         XA_WINDOW, 0, 1);
 
   if (proto_out)
     xdnd_proto_cookie = xcb_get_property (dpyinfo->xcb_connection, 0,
                                          (xcb_window_t) wdesc,
                                          (xcb_atom_t) dpyinfo->Xatom_XdndAware,
-                                         XCB_ATOM_ATOM, 0, 1);
+                                         XA_ATOM, 0, 1);
 
   if (proxy_out)
     {
@@ -3603,7 +3667,7 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, 
Window wdesc,
       else
        {
          if (reply->format == 32
-             && reply->type == XCB_ATOM_WINDOW
+             && reply->type == XA_WINDOW
              && (xcb_get_property_value_length (reply) >= 4))
            *proxy_out = *(xcb_window_t *) xcb_get_property_value (reply);
 
@@ -3621,7 +3685,7 @@ x_dnd_get_proxy_proto (struct x_display_info *dpyinfo, 
Window wdesc,
       else
        {
          if (reply->format == 32
-             && reply->type == XCB_ATOM_ATOM
+             && reply->type == XA_ATOM
              && (xcb_get_property_value_length (reply) >= 4))
            *proto_out = (int) *(xcb_atom_t *) xcb_get_property_value (reply);
 
@@ -3805,15 +3869,15 @@ x_dnd_get_wm_state_and_proto (struct x_display_info 
*dpyinfo,
   wmstate_cookie = xcb_get_property (dpyinfo->xcb_connection, 0,
                                     (xcb_window_t) window,
                                     (xcb_atom_t) dpyinfo->Xatom_wm_state,
-                                    XCB_ATOM_ANY, 0, 2);
+                                    0, 0, 2);
   xdnd_proto_cookie = xcb_get_property (dpyinfo->xcb_connection, 0,
                                        (xcb_window_t) window,
                                        (xcb_atom_t) dpyinfo->Xatom_XdndAware,
-                                       XCB_ATOM_ATOM, 0, 1);
+                                       XA_ATOM, 0, 1);
   xdnd_proxy_cookie = xcb_get_property (dpyinfo->xcb_connection, 0,
                                        (xcb_window_t) window,
                                        (xcb_atom_t) dpyinfo->Xatom_XdndProxy,
-                                       XCB_ATOM_WINDOW, 0, 1);
+                                       XA_WINDOW, 0, 1);
   xm_style_cookie = xcb_get_property (dpyinfo->xcb_connection, 0,
                                      (xcb_window_t) window,
                                      (xcb_atom_t) 
dpyinfo->Xatom_MOTIF_DRAG_RECEIVER_INFO,
@@ -3860,7 +3924,7 @@ x_dnd_get_wm_state_and_proto (struct x_display_info 
*dpyinfo,
   else
     {
       if (reply->format == 32
-         && reply->type == XCB_ATOM_WINDOW
+         && reply->type == XA_WINDOW
          && (xcb_get_property_value_length (reply) >= 4))
        *proxy_out = *(xcb_window_t *) xcb_get_property_value (reply);
 
@@ -3976,6 +4040,12 @@ x_dnd_do_unsupported_drop (struct x_display_info 
*dpyinfo,
   if (owner != FRAME_X_WINDOW (f))
     return;
 
+  /* mouse-drag-and-drop-region will immediately deactivate the mark
+     after this is set.  Make sure the primary selection is not
+     clobbered in that case by setting `deactivate-mark' to
+     Qdont_save.  */
+  Vdeactivate_mark = Qdont_save;
+
   event.xbutton.window = child;
   event.xbutton.subwindow = None;
   event.xbutton.x = dest_x;
@@ -3989,7 +4059,7 @@ x_dnd_do_unsupported_drop (struct x_display_info *dpyinfo,
   event.xbutton.type = ButtonPress;
   event.xbutton.time = before + 1;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (dpyinfo->display, child,
              True, ButtonPressMask, &event);
 
@@ -4501,7 +4571,7 @@ x_dnd_send_enter (struct frame *f, Window target, Window 
toplevel,
      so we don't have to set it again.  */
   x_dnd_init_type_lists = true;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -4573,7 +4643,7 @@ x_dnd_send_position (struct frame *f, Window target, 
Window toplevel,
            return;
        }
 
-      x_ignore_errors_for_next_request (dpyinfo);
+      x_ignore_errors_for_next_request (dpyinfo, 0);
       XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
       x_stop_ignoring_errors (dpyinfo);
 
@@ -4600,7 +4670,7 @@ x_dnd_send_leave (struct frame *f, Window target, Window 
toplevel)
   x_dnd_waiting_for_status_window = None;
   x_dnd_pending_send_position.type = 0;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -4633,7 +4703,7 @@ x_dnd_send_drop (struct frame *f, Window target, Window 
toplevel,
   if (supported >= 1)
     msg.xclient.data.l[2] = timestamp;
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg);
   x_stop_ignoring_errors (dpyinfo);
   return true;
@@ -6745,7 +6815,7 @@ x_set_frame_alpha (struct frame *f)
      Do this unconditionally as this function is called on reparent when
      alpha has not changed on the frame.  */
 
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
 
   if (!FRAME_PARENT_FRAME (f))
     {
@@ -6921,6 +6991,7 @@ static void
 x_sync_wait_for_frame_drawn_event (struct frame *f)
 {
   XEvent event;
+  struct x_display_info *dpyinfo;
 
   if (!FRAME_X_WAITING_FOR_DRAW (f)
       /* The compositing manager can't draw a frame if it is
@@ -6928,6 +6999,8 @@ x_sync_wait_for_frame_drawn_event (struct frame *f)
       || !FRAME_VISIBLE_P (f))
     return;
 
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
   /* Wait for the frame drawn message to arrive.  */
   if (x_if_event (FRAME_X_DISPLAY (f), &event,
                  x_sync_is_frame_drawn_event, (XPointer) f,
@@ -6943,6 +7016,11 @@ x_sync_wait_for_frame_drawn_event (struct frame *f)
                   "been disabled\n");
          FRAME_X_OUTPUT (f)->use_vsync_p = false;
 
+         /* Remove the compositor bypass property from the outer
+            window.  */
+         XDeleteProperty (dpyinfo->display, FRAME_OUTER_WINDOW (f),
+                          dpyinfo->Xatom_net_wm_bypass_compositor);
+
          /* Also change the frame parameter to reflect the new
             state.  */
          store_frame_param (f, Quse_frame_synchronization, Qnil);
@@ -6956,7 +7034,7 @@ x_sync_wait_for_frame_drawn_event (struct frame *f)
        }
     }
   else
-    x_sync_note_frame_times (FRAME_DISPLAY_INFO (f), f, &event);
+    x_sync_note_frame_times (dpyinfo, f, &event);
 
   FRAME_X_WAITING_FOR_DRAW (f) = false;
 }
@@ -11005,6 +11083,31 @@ x_clear_frame (struct frame *f)
   unblock_input ();
 }
 
+/* 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
+   after displaying or hiding the hourglass.  */
+
+static void
+x_send_hourglass_message (struct frame *f, bool hourglass_enabled)
+{
+  struct x_display_info *dpyinfo;
+  XEvent msg;
+
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+  memset (&msg, 0, sizeof msg);
+
+  msg.xclient.type = ClientMessage;
+  msg.xclient.message_type
+    = dpyinfo->Xatom_EMACS_TMP;
+  msg.xclient.format = 8;
+  msg.xclient.window = FRAME_X_WINDOW (f);
+  msg.xclient.data.b[0] = hourglass_enabled ? 1 : 0;
+
+  XSendEvent (dpyinfo->display, FRAME_X_WINDOW (f),
+             False, NoEventMask, &msg);
+}
+
 /* RIF: Show hourglass cursor on frame F.  */
 
 static void
@@ -11025,14 +11128,14 @@ x_show_hourglass (struct frame *f)
       if (popup_activated ())
        return;
 
+      x_send_hourglass_message (f, true);
+
 #ifdef USE_X_TOOLKIT
       if (x->widget)
 #else
       if (FRAME_OUTER_WINDOW (f))
 #endif
        {
-         x->hourglass_p = true;
-
          if (!x->hourglass_window)
            {
 #ifndef USE_XCB
@@ -11099,15 +11202,11 @@ x_hide_hourglass (struct frame *f)
     {
 #ifndef USE_XCB
       XUnmapWindow (FRAME_X_DISPLAY (f), x->hourglass_window);
-      /* Sync here because XTread_socket looks at the
-        hourglass_p flag that is reset to zero below.  */
-      XSync (FRAME_X_DISPLAY (f), False);
 #else
       xcb_unmap_window (FRAME_DISPLAY_INFO (f)->xcb_connection,
                        (xcb_window_t) x->hourglass_window);
-      xcb_aux_sync (FRAME_DISPLAY_INFO (f)->xcb_connection);
 #endif
-      x->hourglass_p = false;
+      x_send_hourglass_message (f, false);
     }
 }
 
@@ -11231,21 +11330,32 @@ XTflash (struct frame *f)
 static void
 XTring_bell (struct frame *f)
 {
-  if (FRAME_X_DISPLAY (f))
+  struct x_display_info *dpyinfo;
+
+  if (!FRAME_X_DISPLAY (f))
+    return;
+
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  if (visible_bell)
+    XTflash (f);
+  else
     {
-      if (visible_bell)
-       XTflash (f);
-      else
-       {
-         block_input ();
+      /* When Emacs is untrusted, Bell requests sometimes generate
+        Access errors.  This is not in the security extension
+        specification but seems to be a bug in the X consortium XKB
+        implementation.  */
+
+      block_input ();
+      x_ignore_errors_for_next_request (dpyinfo, 0);
 #ifdef HAVE_XKB
-          XkbBell (FRAME_X_DISPLAY (f), None, 0, None);
+      XkbBell (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), 0, None);
 #else
-         XBell (FRAME_X_DISPLAY (f), 0);
+      XBell (FRAME_X_DISPLAY (f), 0);
 #endif
-         XFlush (FRAME_X_DISPLAY (f));
-         unblock_input ();
-       }
+      XFlush (FRAME_X_DISPLAY (f));
+      x_stop_ignoring_errors (dpyinfo);
+      unblock_input ();
     }
 }
 
@@ -11491,7 +11601,7 @@ x_frame_highlight (struct frame *f)
      the window-manager in use, tho something more is at play since I've been
      using that same window-manager binary for ever.  Let's not crash just
      because of this (bug#9310).  */
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                    f->output_data.x->border_pixel);
   x_stop_ignoring_errors (dpyinfo);
@@ -11514,7 +11624,7 @@ x_frame_unhighlight (struct frame *f)
 
   block_input ();
   /* Same as above for XSetWindowBorder (bug#9310).  */
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
                          f->output_data.x->border_tile);
   x_stop_ignoring_errors (dpyinfo);
@@ -12277,6 +12387,13 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, 
Atom xaction,
   struct xi_device_t *device;
 #endif
 
+  if (FRAME_DISPLAY_INFO (f)->untrusted)
+    /* Untrusted clients cannot send messages to trusted clients or
+       read the window tree, so drag and drop will likely not work at
+       all.  */
+    error ("Drag-and-drop is not possible when the client is"
+          " not trusted by the X server.");
+
   base = SPECPDL_INDEX ();
 
   /* Bind this here to avoid juggling bindings and SAFE_FREE in
@@ -15048,9 +15165,7 @@ x_send_scroll_bar_event (Lisp_Object window, enum 
scroll_bar_part part,
   XClientMessageEvent *ev = &event.xclient;
   struct window *w = XWINDOW (window);
   struct frame *f = XFRAME (w->frame);
-  intptr_t iw = (intptr_t) w;
   verify (INTPTR_WIDTH <= 64);
-  int sign_shift = INTPTR_WIDTH - 32;
 
   /* Don't do anything if too many scroll bar events have been
      sent but not received.  */
@@ -15067,15 +15182,11 @@ x_send_scroll_bar_event (Lisp_Object window, enum 
scroll_bar_part part,
   ev->window = FRAME_X_WINDOW (f);
   ev->format = 32;
 
-  /* A 32-bit X client can pass a window pointer through the X server
-     as-is.
-
-     A 64-bit client is in trouble because a pointer does not fit in
-     the 32 bits given for ClientMessage data and will be truncated by
-     Xlib.  So use two slots and hope that X12 will resolve such
-     issues someday.  */
-  ev->data.l[0] = iw >> 31 >> 1;
-  ev->data.l[1] = sign_shift <= 0 ? iw : iw << sign_shift >> sign_shift;
+  /* These messages formerly contained a pointer to the window, but
+     now that information is kept internally.  The following two
+     fields are thus zero.  */
+  ev->data.l[0] = 0;
+  ev->data.l[1] = 0;
   ev->data.l[2] = part;
   ev->data.l[3] = portion;
   ev->data.l[4] = whole;
@@ -18506,7 +18617,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                      x_dnd_waiting_for_status_window = None;
                    else
                      {
-                       x_ignore_errors_for_next_request (dpyinfo);
+                       x_ignore_errors_for_next_request (dpyinfo, 0);
                        XSendEvent (dpyinfo->display, target,
                                    False, NoEventMask,
                                    &x_dnd_pending_send_position);
@@ -18620,6 +18731,16 @@ handle_one_xevent (struct x_display_info *dpyinfo,
              }
          }
 
+       if (event->xclient.message_type == dpyinfo->Xatom_EMACS_TMP
+           && event->xclient.format == 8)
+         {
+           /* This is actually an hourglass message.  Set whether or
+              not events from here on have the hourglass enabled.  */
+
+           if (any)
+             FRAME_X_OUTPUT (any)->hourglass_p = event->xclient.data.b[0];
+         }
+
         if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols
             && event->xclient.format == 32)
           {
@@ -19208,7 +19329,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                = xcb_get_property (dpyinfo->xcb_connection, 0,
                                    (xcb_window_t) FRAME_OUTER_WINDOW (f),
                                    (xcb_atom_t) 
dpyinfo->Xatom_net_wm_window_opacity,
-                                   XCB_ATOM_CARDINAL, 0, 1);
+                                   XA_CARDINAL, 0, 1);
              opacity_reply
                = xcb_get_property_reply (dpyinfo->xcb_connection,
                                          opacity_cookie, &error);
@@ -19217,9 +19338,9 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                free (error), rc = false;
              else
                rc = (opacity_reply->format == 32
-                     && (opacity_reply->type == XCB_ATOM_CARDINAL
-                         || opacity_reply->type == XCB_ATOM_ATOM
-                         || opacity_reply->type == XCB_ATOM_WINDOW)
+                     && (opacity_reply->type == XA_CARDINAL
+                         || opacity_reply->type == XA_ATOM
+                         || opacity_reply->type == XA_WINDOW)
                      && (xcb_get_property_value_length (opacity_reply) >= 4));
 
              if (rc)
@@ -21365,7 +21486,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 
            if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
              {
-               x_ignore_errors_for_next_request (dpyinfo);
+               x_ignore_errors_for_next_request (dpyinfo, 0);
                XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
                                RevertToParent, event->xbutton.time);
                x_stop_ignoring_errors (dpyinfo);
@@ -23063,7 +23184,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                          /* This can generate XI_BadDevice if the
                             device's attachment was destroyed
                             server-side.  */
-                         x_ignore_errors_for_next_request (dpyinfo);
+                         x_ignore_errors_for_next_request (dpyinfo, 0);
                          XISetFocus (dpyinfo->display, device->attachment,
                                      /* Note that the input extension
                                         only supports RevertToParent-type
@@ -23076,7 +23197,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
                         events to handle focus.  Errors are still
                         caught here in case the window is not
                         viewable.  */
-                     x_ignore_errors_for_next_request (dpyinfo);
+                     x_ignore_errors_for_next_request (dpyinfo, 0);
                      XSetInputFocus (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW 
(f),
                                      RevertToParent, xev->time);
                      x_stop_ignoring_errors (dpyinfo);
@@ -24085,7 +24206,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifndef HAVE_GTK3
                  else if (x_input_grab_touch_events)
                    {
-                     x_ignore_errors_for_next_request (dpyinfo);
+                     x_ignore_errors_for_next_request (dpyinfo, 0);
                      XIAllowTouchEvents (dpyinfo->display, xev->deviceid,
                                          xev->detail, xev->event, 
XIRejectTouch);
                      x_stop_ignoring_errors (dpyinfo);
@@ -25522,10 +25643,17 @@ x_clean_failable_requests (struct x_display_info 
*dpyinfo)
    x_uncatch_errors_after_check is that this function does not sync to
    catch errors if requests were made.  It should be used instead of
    those two functions for catching errors around requests that do not
-   require a reply.  */
+   require a reply.
+
+   As a special feature intended to support xselect.c,
+   SELECTION_SERIAL may be an arbitrary number greater than zero: when
+   that is the case, x_select_handle_selection_error is called with
+   the specified number to delete the selection request that
+   encountered the error.  */
 
 void
-x_ignore_errors_for_next_request (struct x_display_info *dpyinfo)
+x_ignore_errors_for_next_request (struct x_display_info *dpyinfo,
+                                 unsigned int selection_serial)
 {
   struct x_failable_request *request, *max;
   unsigned long next_request;
@@ -25579,6 +25707,7 @@ x_ignore_errors_for_next_request (struct x_display_info 
*dpyinfo)
 
   request->start = next_request;
   request->end = 0;
+  request->selection_serial = selection_serial;
 
   dpyinfo->next_failable_request++;
 }
@@ -26000,9 +26129,11 @@ For details, see etc/PROBLEMS.\n",
          if (!ioerror && dpyinfo)
            {
              /* Dump the list of error handlers for debugging
-                purposes.  */
+                purposes if the list exists.  */
 
-             fprintf (stderr, "X error handlers currently installed:\n");
+             if ((dpyinfo->failable_requests
+                  != dpyinfo->next_failable_request) || x_error_message)
+               fprintf (stderr, "X error handlers currently installed:\n");
 
              for (failable = dpyinfo->failable_requests;
                   failable < dpyinfo->next_failable_request;
@@ -26091,6 +26222,12 @@ x_error_handler (Display *display, XErrorEvent *event)
                                                + (last - fail));
            }
 
+         /* If a selection transfer is the cause of this error,
+            remove the selection transfer now.  */
+         if (fail->selection_serial)
+           x_handle_selection_error (fail->selection_serial,
+                                     event);
+
          return 0;
        }
     }
@@ -26643,38 +26780,43 @@ x_set_offset (struct frame *f, int xoff, int yoff, 
int change_gravity)
               modified_left, modified_top);
 #endif
 
-  /* 'x_sync_with_move' is too costly for dragging child frames.  */
-  if (!FRAME_PARENT_FRAME (f)
-      /* If no window manager exists, just calling XSync will be
-        sufficient to ensure that the window geometry has been
-        updated.  */
-      && NILP (Vx_no_window_manager))
-    {
-      x_sync_with_move (f, f->left_pos, f->top_pos,
-                       FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
-
-      /* change_gravity is non-zero when this function is called from Lisp to
-        programmatically move a frame.  In that case, we call
-        x_check_expected_move to discover if we have a "Type A" or "Type B"
-        window manager, and, for a "Type A" window manager, adjust the position
-        of the frame.
-
-        We call x_check_expected_move if a programmatic move occurred, and
-        either the window manager type (A/B) is unknown or it is Type A but we
-        need to compute the top/left offset adjustment for this frame.  */
-
-      if (change_gravity != 0
-         && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
-             || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
-                 && (FRAME_X_OUTPUT (f)->move_offset_left == 0
-                     && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
-       x_check_expected_move (f, modified_left, modified_top);
-    }
-  /* Instead, just wait for the last ConfigureWindow request to
-     complete.  No window manager is involved when moving child
-     frames.  */
-  else
-    XSync (FRAME_X_DISPLAY (f), False);
+  /* The following code is too slow over a latent network
+     connection.  */
+  if (NILP (Vx_lax_frame_positioning))
+    {
+      /* 'x_sync_with_move' is too costly for dragging child frames.  */
+      if (!FRAME_PARENT_FRAME (f)
+         /* If no window manager exists, just calling XSync will be
+            sufficient to ensure that the window geometry has been
+            updated.  */
+         && NILP (Vx_no_window_manager))
+       {
+         x_sync_with_move (f, f->left_pos, f->top_pos,
+                           FRAME_DISPLAY_INFO (f)->wm_type == 
X_WMTYPE_UNKNOWN);
+
+         /* change_gravity is non-zero when this function is called from Lisp 
to
+            programmatically move a frame.  In that case, we call
+            x_check_expected_move to discover if we have a "Type A" or "Type B"
+            window manager, and, for a "Type A" window manager, adjust the 
position
+            of the frame.
+
+            We call x_check_expected_move if a programmatic move occurred, and
+            either the window manager type (A/B) is unknown or it is Type A 
but we
+            need to compute the top/left offset adjustment for this frame.  */
+
+         if (change_gravity != 0
+             && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+                 || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+                     && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+                         && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+           x_check_expected_move (f, modified_left, modified_top);
+       }
+      /* Instead, just wait for the last ConfigureWindow request to
+        complete.  No window manager is involved when moving child
+        frames.  */
+      else
+       XSync (FRAME_X_DISPLAY (f), False);
+    }
 
   unblock_input ();
 }
@@ -26734,6 +26876,12 @@ x_wm_supports_1 (struct x_display_info *dpyinfo, Atom 
want_atom)
   if (!NILP (Vx_no_window_manager))
     return false;
 
+  /* If the window system says Emacs is untrusted, there will be no
+     way to send any information to the window manager, making any
+     hints useless.  */
+  if (dpyinfo->untrusted)
+    return false;
+
   block_input ();
 
   x_catch_errors (dpy);
@@ -27477,6 +27625,12 @@ x_set_window_size_1 (struct frame *f, bool 
change_gravity,
      we have to make sure to do it here.  */
   SET_FRAME_GARBAGED (f);
 
+  /* The following code is too slow over a latent network
+     connection, so skip it when the user says so.  */
+
+  if (!NILP (Vx_lax_frame_positioning))
+    return;
+
   /* Now, strictly speaking, we can't be sure that this is accurate,
      but the window manager will get around to dealing with the size
      change request eventually, and we'll hear how it went when the
@@ -27570,7 +27724,7 @@ frame_set_mouse_pixel_position (struct frame *f, int 
pix_x, int pix_y)
       && deviceid != -1)
     {
       block_input ();
-      x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f));
+      x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0);
       XIWarpPointer (FRAME_X_DISPLAY (f), deviceid, None,
                     FRAME_X_WINDOW (f), 0, 0, 0, 0, pix_x, pix_y);
       x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f));
@@ -27867,7 +28021,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, 
Window window,
        {
          eassert (device->use == XIMasterPointer);
 
-         x_ignore_errors_for_next_request (dpyinfo);
+         x_ignore_errors_for_next_request (dpyinfo, 0);
          XISetFocus (dpyinfo->display, device->attachment,
                      /* Note that the input extension
                         only supports RevertToParent-type
@@ -27882,7 +28036,7 @@ x_set_input_focus (struct x_display_info *dpyinfo, 
Window window,
 
   /* Otherwise, use the pointer device that the X server says is the
      client pointer.  */
-  x_ignore_errors_for_next_request (dpyinfo);
+  x_ignore_errors_for_next_request (dpyinfo, 0);
   XSetInputFocus (dpyinfo->display, window, RevertToParent, time);
   x_stop_ignoring_errors (dpyinfo);
 }
@@ -27902,12 +28056,17 @@ x_focus_frame (struct frame *f, bool noactivate)
   struct x_display_info *dpyinfo;
   Time time;
 
+  dpyinfo = FRAME_DISPLAY_INFO (f);
+
+  if (dpyinfo->untrusted)
+    /* The X server ignores all input focus related requests from
+       untrusted clients.  */
+    return;
+
   /* The code below is not reentrant wrt to dpyinfo->x_focus_frame and
      friends being set.  */
   block_input ();
 
-  dpyinfo = FRAME_DISPLAY_INFO (f);
-
   if (FRAME_X_EMBEDDED_P (f))
     /* For Xembedded frames, normally the embedder forwards key
        events.  See XEmbed Protocol Specification at
@@ -28019,7 +28178,7 @@ xembed_send_message (struct frame *f, Time t, enum 
xembed_message msg,
      but I don't understand why: there is no way for clients to
      survive the death of the parent anyway.  */
 
-  x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f));
+  x_ignore_errors_for_next_request (FRAME_DISPLAY_INFO (f), 0);
   XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_OUTPUT (f)->parent_desc,
              False, NoEventMask, &event);
   x_stop_ignoring_errors (FRAME_DISPLAY_INFO (f));
@@ -28170,6 +28329,7 @@ x_make_frame_visible (struct frame *f)
        && !FRAME_ICONIFIED_P (f)
        && !FRAME_X_EMBEDDED_P (f)
        && !FRAME_PARENT_FRAME (f)
+       && NILP (Vx_lax_frame_positioning)
        && f->win_gravity == NorthWestGravity
        && previously_visible)
       {
@@ -28198,7 +28358,8 @@ x_make_frame_visible (struct frame *f)
       }
 
     /* Try to wait for a MapNotify event (that is what tells us when a
-       frame becomes visible).  */
+       frame becomes visible).  Unless `x-lax-frame-positioning' is
+       non-nil: there, that is a little slow.  */
 
 #ifdef CYGWIN
     /* On Cygwin, which uses input polling, we need to force input to
@@ -28216,7 +28377,8 @@ x_make_frame_visible (struct frame *f)
     poll_suppress_count = old_poll_suppress_count;
 #endif
 
-    if (!FRAME_VISIBLE_P (f))
+    if (!FRAME_VISIBLE_P (f)
+       && NILP (Vx_lax_frame_positioning))
       {
        if (CONSP (frame_size_history))
          frame_size_history_plain
@@ -28273,7 +28435,7 @@ x_make_frame_invisible (struct frame *f)
        error ("Can't notify window manager of window withdrawal");
       }
 
-  x_sync (f);
+  XSync (FRAME_X_DISPLAY (f), False);
 
   /* We can't distinguish this from iconification
      just by the event that we get from the server.
@@ -29466,6 +29628,7 @@ struct x_display_info *
 x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
 {
   Display *dpy;
+  XKeyboardState keyboard_state;
   struct terminal *terminal;
   struct x_display_info *dpyinfo;
   XrmDatabase xrdb;
@@ -29685,6 +29848,32 @@ x_term_init (Lisp_Object display_name, char 
*xrm_option, char *resource_name)
   dpyinfo = xzalloc (sizeof *dpyinfo);
   terminal = x_create_terminal (dpyinfo);
 
+  if (!NILP (Vx_detect_server_trust))
+    {
+      /* Detect whether or not the X server trusts this client, which
+        is done by making a SetKeyboardControl request and checking
+        for an Access error.  */
+      XGrabServer (dpy);
+      XGetKeyboardControl (dpy, &keyboard_state);
+
+      x_catch_errors (dpy);
+
+      /* At this point, the display is not on x_display_list, so
+        x_uncatch_errors won't sync.  However, that's okay because
+        x_had_errors_p will.  */
+
+      if (keyboard_state.global_auto_repeat
+         == AutoRepeatModeOn)
+       XAutoRepeatOn (dpy);
+      else
+       XAutoRepeatOff (dpy);
+
+      if (x_had_errors_p (dpy))
+       dpyinfo->untrusted = true;
+      x_uncatch_errors_after_check ();
+      XUngrabServer (dpy);
+    }
+
   dpyinfo->next_failable_request = dpyinfo->failable_requests;
 
   {
@@ -31169,7 +31358,7 @@ x_catch_errors_for_lisp (struct x_display_info *dpyinfo)
   if (!x_fast_protocol_requests)
     x_catch_errors (dpyinfo->display);
   else
-    x_ignore_errors_for_next_request (dpyinfo);
+    x_ignore_errors_for_next_request (dpyinfo, 0);
 }
 
 void
@@ -31378,6 +31567,8 @@ syms_of_xterm (void)
   DEFSYM (Qnow, "now");
   DEFSYM (Qx_dnd_targets_list, "x-dnd-targets-list");
   DEFSYM (Qx_auto_preserve_selections, "x-auto-preserve-selections");
+  DEFSYM (Qexpose, "expose");
+  DEFSYM (Qdont_save, "dont-save");
 
 #ifdef USE_GTK
   xg_default_icon_file = build_pure_c_string 
("icons/hicolor/scalable/apps/emacs.svg");
@@ -31547,7 +31738,6 @@ always uses gtk_window_move and ignores the value of 
this variable.  */);
 This option is only effective when Emacs is built with XInput 2
 support. */);
   Vx_scroll_event_delta_factor = make_float (1.0);
-  DEFSYM (Qexpose, "expose");
 
   DEFVAR_BOOL ("x-gtk-use-native-input", x_gtk_use_native_input,
               doc: /* Non-nil means to use GTK for input method support.
@@ -31761,4 +31951,25 @@ select text over slow X connections.
 If that is still too slow, setting this variable to the symbol
 `really-fast' will make Emacs return only cached values.  */);
   Vx_use_fast_mouse_position = Qnil;
+
+  DEFVAR_LISP ("x-detect-server-trust", Vx_detect_server_trust,
+    doc: /* If non-nil, Emacs should detect whether or not it is trusted by X.
+
+If non-nil, Emacs will make an X request at connection startup that is
+prohibited to untrusted clients under the X Security Extension and
+check whether or not a resulting Access error is generated by the X
+server.  If the X server reports the error, Emacs will disable certain
+features that do not work for untrusted clients.  */);
+  Vx_detect_server_trust = Qnil;
+
+  DEFVAR_LISP ("x-lax-frame-positioning", Vx_lax_frame_positioning,
+    doc: /* If non-nil, Emacs won't compensate for WM geometry behavior.
+
+Setting this to non-nil is useful when the compensation proves to be
+too slow, which is usually true when the X server is located over a
+network connection with high latency.  Doing so will make frame
+creation and placement faster at the cost of reducing the accuracy of
+frame placement via frame parameters, `set-frame-position', and
+`set-frame-size'.  */);
+  Vx_lax_frame_positioning = Qnil;
 }
diff --git a/src/xterm.h b/src/xterm.h
index fae40930e9..832ffc172b 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -334,6 +334,9 @@ struct x_failable_request
   /* If this is zero, then the request has not yet been made.
      Otherwise, this is the request that ends this sequence.  */
   unsigned long end;
+
+  /* Any selection event serial associated with this error trap.  */
+  unsigned int selection_serial;
 };
 
 #ifdef HAVE_XFIXES
@@ -376,6 +379,10 @@ struct x_display_info
   /* Number of frames that are on this display.  */
   int reference_count;
 
+  /* True if this display connection cannot communicate with the
+     window manager because it is not trusted by the X server.  */
+  bool untrusted;
+
   /* The Screen this connection is connected to.  */
   Screen *screen;
 
@@ -1666,7 +1673,8 @@ extern bool x_had_errors_p (Display *);
 extern void x_unwind_errors_to (int);
 extern void x_uncatch_errors (void);
 extern void x_uncatch_errors_after_check (void);
-extern void x_ignore_errors_for_next_request (struct x_display_info *);
+extern void x_ignore_errors_for_next_request (struct x_display_info *,
+                                             unsigned int);
 extern void x_stop_ignoring_errors (struct x_display_info *);
 extern void x_clear_errors (Display *);
 extern void x_set_window_size (struct frame *, bool, int, int);
@@ -1826,6 +1834,7 @@ extern void x_handle_selection_notify (const 
XSelectionEvent *);
 extern void x_handle_selection_event (struct selection_input_event *);
 extern void x_clear_frame_selections (struct frame *);
 extern void x_remove_selection_transfers (struct x_display_info *);
+extern void x_handle_selection_error (unsigned int, XErrorEvent *);
 
 extern Lisp_Object x_atom_to_symbol (struct x_display_info *, Atom);
 extern Atom symbol_to_x_atom (struct x_display_info *, Lisp_Object);
diff --git a/test/README b/test/README
index 17783a4bac..eb6314c74d 100644
--- a/test/README
+++ b/test/README
@@ -118,7 +118,7 @@ If the $EMACS_TEST_JUNIT_REPORT environment variable is set 
to a file
 name, a JUnit test report is generated under this name.
 
 Some of the tests require a remote temporary directory
-(autorevert-tests.el, dnd-tests.el, filenotify-tests.el,
+(autorevert-tests.el, dnd-tests.el, eglot-tests.el, filenotify-tests.el,
 shadowfile-tests.el and tramp-tests.el).  Per default, a mock-up
 connection method is used (this might not be possible when running on
 MS Windows).  If you want to test a real remote connection, set
diff --git a/test/infra/gitlab-ci.yml b/test/infra/gitlab-ci.yml
index e034430edc..96fe9e3a1c 100644
--- a/test/infra/gitlab-ci.yml
+++ b/test/infra/gitlab-ci.yml
@@ -155,7 +155,7 @@ default:
 .filenotify-gio-template:
   rules:
     - if: '$CI_PIPELINE_SOURCE == "web"'
-    - if: '$CI_PIPELINE_SOURCE == "schedule"'
+    # - if: '$CI_PIPELINE_SOURCE == "schedule"'
       changes:
         - "**.in"
         - lisp/autorevert.el
@@ -246,17 +246,17 @@ test-gnustep:
     target: emacs-gnustep
     make_params: install
 
-build-native-comp-speed0:
-  stage: native-comp-images
-  extends: [.job-template, .build-template, .native-comp-template]
-  variables:
-    target: emacs-native-comp-speed0
+# build-native-comp-speed0:
+#   stage: native-comp-images
+#   extends: [.job-template, .build-template, .native-comp-template]
+#   variables:
+#     target: emacs-native-comp-speed0
 
-build-native-comp-speed1:
-  stage: native-comp-images
-  extends: [.job-template, .build-template, .native-comp-template]
-  variables:
-    target: emacs-native-comp-speed1
+# build-native-comp-speed1:
+#   stage: native-comp-images
+#   extends: [.job-template, .build-template, .native-comp-template]
+#   variables:
+#     target: emacs-native-comp-speed1
 
 build-native-comp-speed2:
   stage: native-comp-images
@@ -264,14 +264,14 @@ build-native-comp-speed2:
   variables:
     target: emacs-native-comp-speed2
 
-test-native-comp-speed0:
+test-native-comp-speed2:
   stage: native-comp
   extends: [.job-template, .test-template, .native-comp-template]
   needs:
-    - job: build-native-comp-speed0
+    - job: build-native-comp-speed2
       optional: true
   variables:
-    target: emacs-native-comp-speed0
+    target: emacs-native-comp-speed2
     make_params: "-k -C test check SELECTOR='(not (tag :unstable))'"
 
 # Local Variables:
diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml
index 51707c181b..55ce590af8 100644
--- a/test/infra/test-jobs.yml
+++ b/test/infra/test-jobs.yml
@@ -493,6 +493,23 @@ test-lisp-url-inotify:
     target: emacs-inotify
     make_params: "-k -C test check-lisp-url"
 
+test-lisp-use-package-inotify:
+  stage: normal
+  extends: [.job-template, .test-template]
+  needs:
+    - job: build-image-inotify
+      optional: true
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "schedule"'
+      when: never
+    - changes:
+        - lisp/use-package/*.el
+        - test/lisp/use-package/*.el
+        - test/lisp/use-package/*resources/**
+  variables:
+    target: emacs-inotify
+    make_params: "-k -C test check-lisp-use-package"
+
 test-lisp-vc-inotify:
   stage: normal
   extends: [.job-template, .test-template]
diff --git a/test/lisp/auth-source-pass-tests.el 
b/test/lisp/auth-source-pass-tests.el
index 1107e09b51..d6d42ce942 100644
--- a/test/lisp/auth-source-pass-tests.el
+++ b/test/lisp/auth-source-pass-tests.el
@@ -175,7 +175,8 @@ HOSTNAME, USER and PORT are passed unchanged to
 (ert-deftest auth-source-pass-any-host ()
   (auth-source-pass--with-store '(("foo" ("port" . "foo-port") ("host" . 
"foo-user"))
                                   ("bar"))
-    (should-not (auth-source-pass-search :host t))))
+    (let ((inhibit-message t)) ; silence "... does not handle host wildcards."
+      (should-not (auth-source-pass-search :host t)))))
 
 (ert-deftest auth-source-pass-undefined-host ()
   (auth-source-pass--with-store '(("foo" ("port" . "foo-port") ("host" . 
"foo-user"))
@@ -697,29 +698,29 @@ machine Libera.Chat password b
 ;; with slightly more realistic and less legible values.
 
 (ert-deftest auth-source-pass-extra-query-keywords--suffixed-user ()
-  (let ((store (sort (copy-sequence '(("x.com:42/b@r" (secret . "a"))
-                                      ("b@r@x.com" (secret . "b"))
+  (let ((store (sort (copy-sequence '(("x.com:42/s p@m" (secret . "a"))
+                                      ("s p@m@x.com" (secret . "b"))
                                       ("x.com" (secret . "?"))
-                                      ("b@r@y.org" (secret . "c"))
-                                      ("fake.com" (secret . "?"))
-                                      ("fake.com/b@r" (secret . "d"))
-                                      ("y.org/b@r" (secret . "?"))
-                                      ("b@r@fake.com" (secret . "e"))))
+                                      ("s p@m@y.org" (secret . "c"))
+                                      ("fa ke" (secret . "?"))
+                                      ("fa ke/s p@m" (secret . "d"))
+                                      ("y.org/s p@m" (secret . "?"))
+                                      ("s p@m@fa ke" (secret . "e"))))
                      (lambda (&rest _) (zerop (random 2))))))
     (auth-source-pass--with-store store
       (auth-source-pass-enable)
       (let* ((auth-source-pass-extra-query-keywords t)
-             (results (auth-source-search :host '("x.com" "fake.com" "y.org")
-                                          :user "b@r"
+             (results (auth-source-search :host '("x.com" "fa ke" "y.org")
+                                          :user "s p@m"
                                           :require '(:user) :max 5)))
         (dolist (result results)
           (setf (plist-get result :secret) (auth-info-password result)))
         (should (equal results
-                       '((:host "x.com" :user "b@r" :secret "b")
-                         (:host "x.com" :user "b@r" :port "42" :secret "a")
-                         (:host "fake.com" :user "b@r" :secret "e")
-                         (:host "fake.com" :user "b@r" :secret "d")
-                         (:host "y.org" :user "b@r" :secret "c"))))))))
+                       '((:host "x.com" :user "s p@m" :secret "b")
+                         (:host "x.com" :user "s p@m" :port "42" :secret "a")
+                         (:host "fa ke" :user "s p@m" :secret "e")
+                         (:host "fa ke" :user "s p@m" :secret "d")
+                         (:host "y.org" :user "s p@m" :secret "c"))))))))
 
 ;; This is a more distilled version of `suffixed-user', above.  It
 ;; better illustrates that search order takes precedence over "/user"
diff --git a/test/lisp/calendar/icalendar-tests.el 
b/test/lisp/calendar/icalendar-tests.el
index fa55eea95e..baf4846c8f 100644
--- a/test/lisp/calendar/icalendar-tests.el
+++ b/test/lisp/calendar/icalendar-tests.el
@@ -63,7 +63,8 @@
 
 (defun icalendar-tests--get-error-string-for-export (diary-string)
   "Call icalendar-export for DIARY-STRING and return resulting error-string."
-  (let ((file (make-temp-file "export.ics")))
+  (ert-with-temp-file file
+    :suffix "-export.ics"
     (with-temp-buffer
       (insert diary-string)
       (icalendar-export-region (point-min) (point-max) file))
diff --git a/test/lisp/comint-tests.el b/test/lisp/comint-tests.el
index 8402c13daf..ce1a6865b6 100644
--- a/test/lisp/comint-tests.el
+++ b/test/lisp/comint-tests.el
@@ -59,9 +59,23 @@
   (dolist (str comint-testsuite-password-strings)
     (should (string-match comint-password-prompt-regexp str))))
 
+(declare-function w32-application-type "w32proc.c")
+(defun w32-native-executable-p (fname)
+  "Predicate to test program FNAME for being a native Windows application."
+  (and (memq (w32-application-type fname) '(w32-native dos))
+       (file-executable-p fname)))
+
+(defun w32-native-executable-find (name)
+  "Find a native MS-Windows application named NAME.
+This is needed to avoid invoking MSYS or Cygwin executables that
+happen to lurk on PATH when running the test suite."
+  (locate-file name exec-path exec-suffixes 'w32-native-executable-p))
+
 (defun comint-tests/test-password-function (password-function)
   "PASSWORD-FUNCTION can return nil or a string."
-  (when-let ((cat (executable-find "cat")))
+  (when-let ((cat (if (eq system-type 'windows-nt)
+                      (w32-native-executable-find "cat")
+                    (executable-find "cat"))))
     (let ((comint-password-function password-function))
       (cl-letf (((symbol-function 'read-passwd)
                  (lambda (&rest _args) "non-nil")))
diff --git a/test/lisp/delim-col-tests.el b/test/lisp/delim-col-tests.el
index 97fa0f1e8f..2bf54d9b44 100644
--- a/test/lisp/delim-col-tests.el
+++ b/test/lisp/delim-col-tests.el
@@ -100,7 +100,7 @@
                             "aaa       [ bbb, cccc    ]        dddd\n"
                             "aa        [ bb,  ccccccc ]        ddd\n"))))))
 
-(ert-deftest delim-col-tests-delimit-colummns-before-after ()
+(ert-deftest delim-col-tests-delimit-columns-before-after ()
   (let ((delimit-columns-before "<")
         (delimit-columns-after ">"))
     (with-temp-buffer
diff --git a/test/lisp/emacs-lisp/bytecomp-tests.el 
b/test/lisp/emacs-lisp/bytecomp-tests.el
index e7c308213e..3400128759 100644
--- a/test/lisp/emacs-lisp/bytecomp-tests.el
+++ b/test/lisp/emacs-lisp/bytecomp-tests.el
@@ -833,13 +833,19 @@ byte-compiled.  Run with dynamic binding."
     ;; Should not warn that mt--test2 is not known to be defined.
     (should-not (re-search-forward "my--test2" nil t))))
 
-(defmacro bytecomp--with-warning-test (re-warning &rest form)
+(defmacro bytecomp--with-warning-test (re-warning form)
   (declare (indent 1))
   `(with-current-buffer (get-buffer-create "*Compile-Log*")
      (let ((inhibit-read-only t)) (erase-buffer))
-     (byte-compile ,@form)
-     (ert-info ((prin1-to-string (buffer-string)) :prefix "buffer: ")
-       (should (re-search-forward ,(string-replace " " "[ \n]+" 
re-warning))))))
+     (let ((text-quoting-style 'grave)
+           (macroexp--warned
+            (make-hash-table :test #'equal :weakness 'key))   ; oh dear
+           (form ,form))
+       (ert-info ((prin1-to-string form) :prefix "form: ")
+         (byte-compile form)
+         (ert-info ((prin1-to-string (buffer-string)) :prefix "buffer: ")
+           (should (re-search-forward
+                    (string-replace " " "[ \n]+" ,re-warning))))))))
 
 (ert-deftest bytecomp-warn-wrong-args ()
   (bytecomp--with-warning-test "remq.*3.*2"
@@ -863,6 +869,56 @@ byte-compiled.  Run with dynamic binding."
   (bytecomp--with-warning-test "defvar.*foo.*wider than.*characters"
     `(defvar foo t ,bytecomp-tests--docstring)))
 
+(ert-deftest bytecomp-warn-dodgy-args-eq ()
+  (dolist (fn '(eq eql))
+    (cl-flet ((msg (type arg)
+                (format
+                 "`%s' called with literal %s that may never match (arg %d)"
+                 fn type arg)))
+      (bytecomp--with-warning-test (msg "list" 1)   `(,fn '(a) 'x))
+      (bytecomp--with-warning-test (msg "string" 2) `(,fn 'x "a"))
+      (bytecomp--with-warning-test (msg "vector" 2) `(,fn 'x [a]))
+      (bytecomp--with-warning-test (msg "function" 2) `(,fn 'x (lambda () 1)))
+      (bytecomp--with-warning-test (msg "function" 2) `(,fn 'x #'(lambda () 
1)))
+      (unless (eq fn 'eql)
+        (bytecomp--with-warning-test (msg "integer" 2) `(,fn 'x #x10000000000))
+        (bytecomp--with-warning-test (msg "float" 2)   `(,fn 'x 1.0))))))
+
+(ert-deftest bytecomp-warn-dodgy-args-memq ()
+  (dolist (fn '(memq memql remq delq assq rassq))
+    (cl-labels
+        ((msg1 (type)
+           (format
+            "`%s' called with literal %s that may never match (arg 1)"
+            fn type))
+         (msg2 (type)
+           (format
+            "`%s' called with literal %s that may never match (element 2 of 
arg 2)"
+            fn type))
+         (lst (elt)
+           (cond ((eq fn 'assq)  `((a . 1) (,elt . 2) (c . 3)))
+                 ((eq fn 'rassq) `((1 . a) (2 . ,elt) (3 . c)))
+                 (t              `(a       ,elt       c))))
+         (form2 (elt)
+           `(,fn 'x ',(lst elt))))
+
+    (bytecomp--with-warning-test (msg1 "list")   `(,fn '(a) '(x)))
+    (bytecomp--with-warning-test (msg1 "string") `(,fn "a" '(x)))
+    (bytecomp--with-warning-test (msg1 "vector") `(,fn [a] '(x)))
+    (bytecomp--with-warning-test (msg1 "function") `(,fn (lambda () 1) '(x)))
+    (bytecomp--with-warning-test (msg1 "function") `(,fn #'(lambda () 1) '(x)))
+    (unless (eq fn 'memql)
+      (bytecomp--with-warning-test (msg1 "integer") `(,fn #x10000000000 '(x)))
+      (bytecomp--with-warning-test (msg1 "float")   `(,fn 1.0 '(x))))
+
+    (bytecomp--with-warning-test (msg2 "list")   (form2 '(b)))
+    (bytecomp--with-warning-test (msg2 "list")   (form2 ''b))
+    (bytecomp--with-warning-test (msg2 "string") (form2 "b"))
+    (bytecomp--with-warning-test (msg2 "vector") (form2 [b]))
+    (unless (eq fn 'memql)
+      (bytecomp--with-warning-test (msg2 "integer") (form2 #x10000000000))
+      (bytecomp--with-warning-test (msg2 "float")   (form2 1.0))))))
+
 (defmacro bytecomp--define-warning-file-test (file re-warning &optional 
reverse)
   `(ert-deftest ,(intern (format "bytecomp/%s" file)) ()
      (with-current-buffer (get-buffer-create "*Compile-Log*")
diff --git a/test/lisp/emacs-lisp/cconv-tests.el 
b/test/lisp/emacs-lisp/cconv-tests.el
index e666fe0a4c..537f6bfe72 100644
--- a/test/lisp/emacs-lisp/cconv-tests.el
+++ b/test/lisp/emacs-lisp/cconv-tests.el
@@ -60,7 +60,7 @@
                    "cl-defun documentation"))
   (should (eq (cconv-tests-cl-defun) 'cl-defun-result)))
 
-;; FIXME: The byte-complier croaks on this.  See Bug#28557.
+;; FIXME: The byte-compiler croaks on this.  See Bug#28557.
 ;; (defmacro cconv-tests-defmacro ()
 ;;   (:documentation (concat "defmacro" " documentation"))
 ;;   '(quote defmacro-result))
@@ -70,7 +70,7 @@
 ;;                    "defmacro documentation"))
 ;;   (should (eq (cconv-tests-defmacro) 'defmacro-result)))
 
-;; FIXME: The byte-complier croaks on this.  See Bug#28557.
+;; FIXME: The byte-compiler croaks on this.  See Bug#28557.
 ;; (cl-defmacro cconv-tests-cl-defmacro ()
 ;;   (:documentation (concat "cl-defmacro" " documentation"))
 ;;   '(quote cl-defmacro-result))
diff --git a/test/lisp/emacs-lisp/checkdoc-tests.el 
b/test/lisp/emacs-lisp/checkdoc-tests.el
index 289476f024..c17415cbdd 100644
--- a/test/lisp/emacs-lisp/checkdoc-tests.el
+++ b/test/lisp/emacs-lisp/checkdoc-tests.el
@@ -130,25 +130,25 @@ See the comments in Bug#24998."
     (re-search-forward goto-string)
     (checkdoc-in-abbreviation-p (point))))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p/basic-case ()
+(ert-deftest checkdoc-tests-in-abbreviation-p/basic-case ()
   (should (checkdoc-tests--abbrev-test "foo bar e.g. baz" "e.g"))
   (should (checkdoc-tests--abbrev-test "behavior/errors etc. that" "etc"))
   (should (checkdoc-tests--abbrev-test "foo vs. bar" "vs"))
   (should (checkdoc-tests--abbrev-test "spy a.k.a. spy" "a.k.a")))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p/with-parens ()
+(ert-deftest checkdoc-tests-in-abbreviation-p/with-parens ()
   (should (checkdoc-tests--abbrev-test "foo bar (e.g. baz)" "e.g")))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p/with-escaped-parens ()
+(ert-deftest checkdoc-tests-in-abbreviation-p/with-escaped-parens ()
   (should (checkdoc-tests--abbrev-test "foo\n\\(e.g. baz)" "e.g")))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p/single-char ()
+(ert-deftest checkdoc-tests-in-abbreviation-p/single-char ()
   (should (checkdoc-tests--abbrev-test "a. foo bar" "a")))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p/with-em-dash ()
+(ert-deftest checkdoc-tests-in-abbreviation-p/with-em-dash ()
   (should (checkdoc-tests--abbrev-test "foo bar baz---e.g." "e.g")))
 
-(ert-deftest checkdoc-tests-in-abbrevation-p/incorrect-abbreviation ()
+(ert-deftest checkdoc-tests-in-abbreviation-p/incorrect-abbreviation ()
   (should-not (checkdoc-tests--abbrev-test "foo bar a.b.c." "a.b.c")))
 
 (defun checkdoc-test-error-format-is-good (msg &optional reverse literal)
diff --git a/test/lisp/emacs-lisp/cl-lib-tests.el 
b/test/lisp/emacs-lisp/cl-lib-tests.el
index b19494af74..759138569e 100644
--- a/test/lisp/emacs-lisp/cl-lib-tests.el
+++ b/test/lisp/emacs-lisp/cl-lib-tests.el
@@ -404,7 +404,7 @@
 (ert-deftest cl-lib-nth-value-test-multiple-values ()
   "While CL multiple values are an alias to list, these won't work."
   :expected-result :failed
-  (should (eq (cl-nth-value 0 '(2 3)) '(2 3)))
+  (should (equal (cl-nth-value 0 '(2 3)) '(2 3)))
   (should (= (cl-nth-value 0 1) 1))
   (should (null (cl-nth-value 1 1)))
   (should-error (cl-nth-value -1 (cl-values 2 3)) :type 'args-out-of-range)
@@ -431,7 +431,8 @@
     (should (eq nums (cdr (cl-adjoin 3 nums))))
     ;; add only when not already there
     (should (eq nums (cl-adjoin 2 nums)))
-    (should (equal '(2 1 (2)) (cl-adjoin 2 '(1 (2)))))
+    (with-suppressed-warnings ((suspicious eq))
+      (should (equal '(2 1 (2)) (cl-adjoin 2 '(1 (2))))))
     ;; default test function is eql
     (should (equal '(1.0 1 2) (cl-adjoin 1.0 nums)))
     ;; own :test function - returns true if match
diff --git a/test/lisp/emacs-lisp/find-func-tests.el 
b/test/lisp/emacs-lisp/find-func-tests.el
index d18a9dc1a9..8c432f8720 100644
--- a/test/lisp/emacs-lisp/find-func-tests.el
+++ b/test/lisp/emacs-lisp/find-func-tests.el
@@ -87,7 +87,7 @@ expected function symbol and function library, respectively."
   (test-locate-helper #'forward-char '(forward-char . "cmds.c"))
   (should-error (test-locate-helper 'wrong-function)))
 
-(ert-deftest find-func-tests--locate-adviced-symbols ()
+(ert-deftest find-func-tests--locate-advised-symbols ()
   (defun my-message ()
     (message "Hello!"))
   (advice-add #'mark-sexp :around 'my-message)
diff --git a/test/lisp/emacs-lisp/lisp-mnt-tests.el 
b/test/lisp/emacs-lisp/lisp-mnt-tests.el
index 200be7354a..a4bf834a8e 100644
--- a/test/lisp/emacs-lisp/lisp-mnt-tests.el
+++ b/test/lisp/emacs-lisp/lisp-mnt-tests.el
@@ -4,22 +4,20 @@
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <https://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Code:
 
diff --git a/test/lisp/emacs-lisp/rx-tests.el b/test/lisp/emacs-lisp/rx-tests.el
index 125ddee859..01772e54d8 100644
--- a/test/lisp/emacs-lisp/rx-tests.el
+++ b/test/lisp/emacs-lisp/rx-tests.el
@@ -207,6 +207,12 @@
                    (list 'ok z))
                  '(ok "F"))))
 
+(ert-deftest rx-let-pcase ()
+  "Test `rx-let' around `pcase' with `rx' patterns (bug#59814)."
+  (should (equal (rx-let ((tata "ab"))
+                   (pcase "abc" ((rx tata) 'toto)))
+                 'toto)))
+
 (ert-deftest rx-kleene ()
   "Test greedy and non-greedy repetition operators."
   (should (equal (rx (* "a") (+ "b") (\? "c") (?\s "d")
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el 
b/test/lisp/emacs-lisp/subr-x-tests.el
index 7a3efe9db6..e80d2e17e8 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -707,7 +707,16 @@
     (should (equal (get-text-property 2 'display) '(raise 0.5)))
     (should (equal (get-text-property 5 'display)
                    [(raise 0.5) (height 2.0)]))
-    (should (equal (get-text-property 9 'display) '(raise 0.5)))))
+    (should (equal (get-text-property 9 'display) '(raise 0.5))))
+  (with-temp-buffer
+    (should (equal (let ((str "some useless string"))
+                     (add-display-text-property 4 8 'height 2.0 str)
+                     (add-display-text-property 2 12 'raise 0.5 str)
+                     str)
+                   #("some useless string"
+                     2 4 (display (raise 0.5))
+                     4 8 (display ((raise 0.5) (height 2.0)))
+                     8 12 (display (raise 0.5)))))))
 
 (ert-deftest subr-x-named-let ()
   (let ((funs ()))
diff --git a/test/lisp/erc/erc-networks-tests.el 
b/test/lisp/erc/erc-networks-tests.el
index fc12bf7ce3..0a8b5935df 100644
--- a/test/lisp/erc/erc-networks-tests.el
+++ b/test/lisp/erc/erc-networks-tests.el
@@ -197,6 +197,36 @@
 
   (erc-networks-tests--clean-bufs))
 
+;; A non-ERC buffer exists named "bob", and we're killing one of two
+;; ERC target buffers named "bob@<netid>".  The surviving buffer
+;; retains its suffix.
+
+(ert-deftest erc-networks-rename-surviving-target-buffer--query-non-target ()
+  (should (memq #'erc-networks-rename-surviving-target-buffer
+                erc-kill-buffer-hook))
+
+  (let ((existing (get-buffer-create "bob"))
+        (bob-foonet (get-buffer-create "bob@foonet")))
+
+    (with-current-buffer bob-foonet
+      (erc-mode)
+      (setq erc-networks--id (make-erc-networks--id-qualifying
+                              :parts [foonet "bob"] :len 1)
+            erc--target (erc--target-from-string "bob")))
+
+    (with-current-buffer (get-buffer-create "bob@barnet")
+      (erc-mode)
+      (setq erc-networks--id (make-erc-networks--id-qualifying
+                              :parts [barnet "bob"] :len 1)
+            erc--target (erc--target-from-string "bob")))
+
+    (kill-buffer "bob@barnet")
+    (should (buffer-live-p existing))
+    (should (buffer-live-p bob-foonet))
+    (kill-buffer existing))
+
+  (erc-networks-tests--clean-bufs))
+
 (ert-deftest erc-networks-rename-surviving-target-buffer--multi ()
 
   (ert-info ("Multiple leftover channels untouched")
@@ -1171,6 +1201,8 @@
     (let (erc-server-announced-name
           (erc--isupport-params (make-hash-table))
           erc-network
+          erc-quit-hook
+          (erc-server-process (erc-networks-tests--create-live-proc))
           calls)
       (erc-mode)
 
@@ -1183,10 +1215,7 @@
 
         (ert-info ("Signals when table empty and NETWORK param unset")
           (setq erc-server-announced-name "irc.fake.gnu.org")
-          (let ((err (should-error (erc-networks--set-name
-                                    nil (make-erc-response)))))
-            (should (string-match-p "failed" (cadr err)))
-            (should (eq (car err) 'error)))
+          (should (eq 'error (erc-networks--set-name nil (make-erc-response))))
           (should (string-match-p (rx "*** Failed") (car (pop calls)))))))
 
     (erc-networks-tests--clean-bufs)))
diff --git a/test/lisp/erc/erc-scenarios-auth-source.el 
b/test/lisp/erc/erc-scenarios-auth-source.el
index 3d399a1815..20cae9fbcb 100644
--- a/test/lisp/erc/erc-scenarios-auth-source.el
+++ b/test/lisp/erc/erc-scenarios-auth-source.el
@@ -1,28 +1,29 @@
 ;;; erc-scenarios-auth-source.el --- auth-source scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;; Commentary:
-;;
+
 ;; For practical reasons (mainly lack of imagination), this file
 ;; contains tests for both server-password and NickServ contexts.
 
+;;; Code:
+
 (require 'ert-x)
 (eval-and-compile
   (let ((load-path (cons (ert-resource-directory) load-path)))
diff --git a/test/lisp/erc/erc-scenarios-base-association-nick.el 
b/test/lisp/erc/erc-scenarios-base-association-nick.el
index b46c996bc0..7eac9c900a 100644
--- a/test/lisp/erc/erc-scenarios-base-association-nick.el
+++ b/test/lisp/erc/erc-scenarios-base-association-nick.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-association-nick.el --- base assoc scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-association-query.el 
b/test/lisp/erc/erc-scenarios-base-association-query.el
new file mode 100644
index 0000000000..78b75a530c
--- /dev/null
+++ b/test/lisp/erc/erc-scenarios-base-association-query.el
@@ -0,0 +1,107 @@
+;;; erc-scenarios-base-association-query.el --- assoc query scenarios -*- 
lexical-binding: t -*-
+
+;; Copyright (C) 2022 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)))
+
+(eval-when-compile (require 'erc-join))
+
+
+;; Non-ERC buffers exist whose names match the nicknames of query
+;; targets, both newly arriving and outgoing.  No target buffers yet
+;; exist for these, so new ones are created that feature a net-ID
+;; @suffix.
+
+(ert-deftest erc-scenarios-base-association-existing-non-erc-buffer ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/queries")
+       (dumb-server (erc-d-run "localhost" t 'non-erc))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (nitwit (with-current-buffer (get-buffer-create "nitwit")
+                 (prin1 (ert-test-name (ert-running-test)) (current-buffer))
+                 (current-buffer))) ; these are killed on completion by macro
+       (dummy (with-current-buffer (get-buffer-create "dummy")
+                (prin1 (ert-test-name (ert-running-test)) (current-buffer))
+                (current-buffer)))
+       (erc-server-flood-penalty 0.1))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))
+        (funcall expect 15 "debug mode")))
+
+    (ert-info ("Nick dummy queries us")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "dummy@foonet"))
+        (should (erc-query-buffer-p))
+        (funcall expect 5 "hi")
+
+        (ert-info ("We query nick nitwit")
+          (with-current-buffer (erc-cmd-QUERY "nitwit")
+            (should (equal (buffer-name) "nitwit@foonet"))
+            (erc-scenarios-common-say "hola")
+            (funcall expect 5 "ciao")))
+
+        (erc-scenarios-common-say "howdy")
+        (funcall expect 5 "bye")
+        (erc-cmd-QUIT "")))))
+
+;; Someone sending you a PM has the same name as the network (bug#59976)
+
+(ert-deftest erc-scenarios-base-association-some-nick-is-network ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "base/assoc/queries")
+       (dumb-server (erc-d-run "localhost" t 'netnick))
+       (port (process-contact dumb-server :service))
+       (expect (erc-d-t-make-expecter))
+       (erc-server-flood-penalty 0.5))
+
+    (ert-info ("Connect to foonet")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester"
+                                :full-name "tester")
+        (erc-scenarios-common-assert-initial-buf-name nil port)
+        (erc-d-t-wait-for 5 (eq erc-network 'foonet))))
+
+    (ert-info ("Join common channel as nick foonet")
+      (with-current-buffer "foonet"
+        (funcall expect 15 "debug mode")
+        (erc-cmd-JOIN "#chan"))
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+        (funcall expect 5 "welcome")))
+
+    (ert-info ("Nick foonet PMs us")
+      (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "foonet@foonet"))
+        (should (erc-query-buffer-p))
+        (funcall expect 5 "hi")))))
+
+;;; erc-scenarios-base-association-query.el ends here
diff --git a/test/lisp/erc/erc-scenarios-base-association-samenet.el 
b/test/lisp/erc/erc-scenarios-base-association-samenet.el
index b7c7079df3..a843159824 100644
--- a/test/lisp/erc/erc-scenarios-base-association-samenet.el
+++ b/test/lisp/erc/erc-scenarios-base-association-samenet.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-association-samenet.el --- assoc samenet scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-association.el 
b/test/lisp/erc/erc-scenarios-base-association.el
index 83e5101e3a..a03714aa79 100644
--- a/test/lisp/erc/erc-scenarios-base-association.el
+++ b/test/lisp/erc/erc-scenarios-base-association.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-association.el --- base assoc scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el 
b/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
index 2ffa86aff6..81cbaca558 100644
--- a/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
+++ b/test/lisp/erc/erc-scenarios-base-compat-rename-bouncer.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-compat-rename-bouncer.el --- compat-rename scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-local-modules.el 
b/test/lisp/erc/erc-scenarios-base-local-modules.el
index 417705de09..ff92dacb75 100644
--- a/test/lisp/erc/erc-scenarios-base-local-modules.el
+++ b/test/lisp/erc/erc-scenarios-base-local-modules.el
@@ -1,30 +1,29 @@
 ;;; erc-scenarios-local-modules.el --- Local modules tests for ERC -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
 
-;;; Code:
+;; 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:
 
 ;; These tests all use `sasl' because, as of ERC 5.5, it's the one
 ;; and only local module.
 
+;;; Code:
+
 (require 'ert-x)
 (eval-and-compile
   (let ((load-path (cons (ert-resource-directory) load-path)))
diff --git a/test/lisp/erc/erc-scenarios-base-misc-regressions.el 
b/test/lisp/erc/erc-scenarios-base-misc-regressions.el
index 8f5700df14..1cad934b6e 100644
--- a/test/lisp/erc/erc-scenarios-base-misc-regressions.el
+++ b/test/lisp/erc/erc-scenarios-base-misc-regressions.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-misc-regressions.el --- misc regressions scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
index 6c6568cad6..6540d44c4b 100644
--- a/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-id.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-netid-bouncer-id.el --- net-id bouncer ID scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el
index f48e1ef394..135d378c7f 100644
--- a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-base.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-netid-bouncer-recon-base.el --- net-id base scenarios 
-*- lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el
index 72510809ab..fb58be9615 100644
--- a/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer-recon-id.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-netid-bouncer-recon-id.el --- recon ID scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-netid-bouncer.el 
b/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
index d171e1f9f9..432a89b997 100644
--- a/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
+++ b/test/lisp/erc/erc-scenarios-base-netid-bouncer.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-netid-bouncer.el --- net-id bouncer scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-netid-samenet.el 
b/test/lisp/erc/erc-scenarios-base-netid-samenet.el
index 248144d6f9..1436712251 100644
--- a/test/lisp/erc/erc-scenarios-base-netid-samenet.el
+++ b/test/lisp/erc/erc-scenarios-base-netid-samenet.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-network-id-samenet.el --- netid-id samenet scenarios 
-*- lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
@@ -39,6 +40,9 @@
        (erc-server-flood-margin 30)
        erc-serv-buf-a erc-serv-buf-b)
 
+    (when (and id-a (zerop (random 2))) (setq id-a (symbol-name id-a)))
+    (when (and id-b (zerop (random 2))) (setq id-b (symbol-name id-b)))
+
     (ert-info ("Connect to foonet with nick tester")
       (with-current-buffer
           (setq erc-serv-buf-a (erc :server "127.0.0.1"
diff --git a/test/lisp/erc/erc-scenarios-base-reconnect.el 
b/test/lisp/erc/erc-scenarios-base-reconnect.el
index 8762f33b30..2a3dac1251 100644
--- a/test/lisp/erc/erc-scenarios-base-reconnect.el
+++ b/test/lisp/erc/erc-scenarios-base-reconnect.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-reconnect.el --- Base-reconnect scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-renick.el 
b/test/lisp/erc/erc-scenarios-base-renick.el
index bf27f61b3f..69ecc0a7da 100644
--- a/test/lisp/erc/erc-scenarios-base-renick.el
+++ b/test/lisp/erc/erc-scenarios-base-renick.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-renick.el --- Re-nicking scenarios -*- lexical-binding: 
t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-reuse-buffers.el 
b/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
index 8e7e939d04..a8575aa55a 100644
--- a/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
+++ b/test/lisp/erc/erc-scenarios-base-reuse-buffers.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-reuse-buffers.el --- base-reuse-buffers scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-unstable.el 
b/test/lisp/erc/erc-scenarios-base-unstable.el
index 2313a15842..f5b8df6f4a 100644
--- a/test/lisp/erc/erc-scenarios-base-unstable.el
+++ b/test/lisp/erc/erc-scenarios-base-unstable.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-base-unstable.el --- base unstable scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el 
b/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
index 5a5b363f31..0e6f4b7a6b 100644
--- a/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
+++ b/test/lisp/erc/erc-scenarios-base-upstream-recon-soju.el
@@ -1,27 +1,28 @@
 ;;; erc-scenarios-upstream-recon-soju.el --- Upstream soju -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;; Commentary:
-;;
+
 ;; These concern the loss and recovery of a proxy's IRC-side connection.
 
+;;; Code:
+
 (require 'ert-x)
 (eval-and-compile
   (let ((load-path (cons (ert-resource-directory) load-path)))
diff --git a/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el 
b/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
index 6e9a217245..76cf9f4f76 100644
--- a/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
+++ b/test/lisp/erc/erc-scenarios-base-upstream-recon-znc.el
@@ -1,27 +1,28 @@
 ;;; erc-scenarios-upstream-recon-znc.el --- Upstream znc -*- lexical-binding: 
t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;; Commentary:
-;;
+
 ;; These concern the loss and recovery of a proxy's IRC-side connection.
 
+;;; Code:
+
 (require 'ert-x)
 (eval-and-compile
   (let ((load-path (cons (ert-resource-directory) load-path)))
diff --git a/test/lisp/erc/erc-scenarios-internal.el 
b/test/lisp/erc/erc-scenarios-internal.el
index e4e1edb97e..e122443c59 100644
--- a/test/lisp/erc/erc-scenarios-internal.el
+++ b/test/lisp/erc/erc-scenarios-internal.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-internal.el --- Proxy file for erc-d tests -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-join-auth-source.el 
b/test/lisp/erc/erc-scenarios-join-auth-source.el
index 94336db07c..ef200fb6d0 100644
--- a/test/lisp/erc/erc-scenarios-join-auth-source.el
+++ b/test/lisp/erc/erc-scenarios-join-auth-source.el
@@ -1,27 +1,28 @@
 ;;; erc-scenarios-join-auth-source.el --- join-auth-source scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
 ;; TODO add another test with autojoin and channel keys
 
+;;; Code:
+
 (require 'ert-x)
 (eval-and-compile
   (let ((load-path (cons (ert-resource-directory) load-path)))
diff --git a/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el 
b/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
index e2e437321d..4c25c3e4f8 100644
--- a/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
+++ b/test/lisp/erc/erc-scenarios-join-netid-newcmd-id.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-join-netid-newcmd-id.el --- join netid newcmd scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-join-netid-newcmd.el 
b/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
index 1a541a46b3..e54f5fe9ce 100644
--- a/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
+++ b/test/lisp/erc/erc-scenarios-join-netid-newcmd.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-join-netid-newcmd.el --- join netid newcmd scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-join-netid-recon-id.el 
b/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
index 92bdd643de..9a9e4692b6 100644
--- a/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
+++ b/test/lisp/erc/erc-scenarios-join-netid-recon-id.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-join-netid-recon-id.el --- join-netid-recon scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-join-netid-recon.el 
b/test/lisp/erc/erc-scenarios-join-netid-recon.el
index cbdba07e25..9f9244dad2 100644
--- a/test/lisp/erc/erc-scenarios-join-netid-recon.el
+++ b/test/lisp/erc/erc-scenarios-join-netid-recon.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-join-netid-recon.el --- join-netid-recon scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
diff --git a/test/lisp/erc/erc-scenarios-misc.el 
b/test/lisp/erc/erc-scenarios-misc.el
index 8557a77906..f1696088a4 100644
--- a/test/lisp/erc/erc-scenarios-misc.el
+++ b/test/lisp/erc/erc-scenarios-misc.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-misc.el --- Misc scenarios for ERC -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
@@ -97,11 +98,10 @@
                                 :nick "tester"
                                 :full-name "tester")
         (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
-        (let ((err (should-error (sleep-for 1))))
-          (should (string-match-p "Failed to determine" (cadr err))))
         (funcall expect 1 "Failed to determine")
         (funcall expect 1 "Failed to determine")
-        (should-not erc-network)
+        (funcall expect 1 "Connection failed")
+        (should (string-prefix-p "Unknown" (erc-network-name)))
         (should (string= erc-server-announced-name "irc.foonet.org"))))))
 
 ;; Targets that are host/server masks like $*, $$*, and #* are routed
diff --git a/test/lisp/erc/erc-scenarios-sasl.el 
b/test/lisp/erc/erc-scenarios-sasl.el
index 6c5e78d0c8..1e412d53d5 100644
--- a/test/lisp/erc/erc-scenarios-sasl.el
+++ b/test/lisp/erc/erc-scenarios-sasl.el
@@ -1,22 +1,21 @@
 ;;; erc-scenarios-sasl.el --- SASL tests for ERC -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Code:
 
diff --git a/test/lisp/erc/erc-scenarios-services-misc.el 
b/test/lisp/erc/erc-scenarios-services-misc.el
index cb1aa6ff32..44e04e5150 100644
--- a/test/lisp/erc/erc-scenarios-services-misc.el
+++ b/test/lisp/erc/erc-scenarios-services-misc.el
@@ -1,22 +1,23 @@
 ;;; erc-scenarios-services-misc.el --- Services-misc scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
+
+;;; Code:
 
 (require 'ert-x)
 (eval-and-compile
@@ -83,4 +84,63 @@
 
     (should-not (memq 'services erc-modules))))
 
+;; A user with `services' enabled connects, quits, and reconnects.  An
+;; entry in their netrc matches the network ID, which isn't known when
+;; `erc-auth-source-server-function' runs -- initially *or* on
+;; reconnect.  It's only seen by `erc-auth-source-services-function'.
+
+(ert-deftest erc-scenarios-services-auth-source-reconnect ()
+  :tags '(:expensive-test)
+  (erc-scenarios-common-with-cleanup
+      ((erc-scenarios-common-dialog "services/auth-source")
+       (erc-server-flood-penalty 0.1)
+       (dumb-server (erc-d-run "localhost" t 'recon 'recon))
+       (port (process-contact dumb-server :service))
+       (netrc-file (make-temp-file
+                    "auth-source-test" nil nil
+                    "machine FooNet login tester password changeme\n"))
+       (auth-sources (list netrc-file))
+       (auth-source-do-cache nil)
+       (erc-modules (cons 'services erc-modules))
+       (erc-use-auth-source-for-nickserv-password t) ; do consult
+       (erc-prompt-for-nickserv-password nil) ; don't prompt
+       (erc-nickserv-alist
+        (cons '(FooNet
+                "NickServ!NickServ@services.int"
+                "This nickname is registered. Please choose"
+                "NickServ" "IDENTIFY" nil nil "You are now identified for ")
+              erc-nickserv-alist))
+       (expect (erc-d-t-make-expecter))
+       (erc-scenarios-common-extra-teardown (lambda ()
+                                              (delete-file netrc-file))))
+
+    (ert-info ("Server password omitted from initial connection")
+      (with-current-buffer (erc :server "127.0.0.1"
+                                :port port
+                                :nick "tester"
+                                :user "tester"
+                                :full-name "tester")
+        (should (string= (buffer-name) (format "127.0.0.1:%d" port)))
+        (ert-info ("Services module authenticates")
+          (funcall expect 10 "This nickname is registered.")
+          (funcall expect 3 "You are now identified"))
+        (erc-cmd-JOIN "#chan")
+        (with-current-buffer (erc-d-t-wait-for 10 (get-buffer "#chan"))
+          (funcall expect 10 "the gallants desire it"))
+        (erc-cmd-QUIT "")
+        (funcall expect 3 "finished")))
+
+    (ert-info ("Server password withheld on reconnect")
+      (with-current-buffer "#chan"
+        (erc-cmd-RECONNECT))
+      (with-current-buffer "FooNet"
+        (funcall expect 10 "This nickname is registered.")
+        (funcall expect 3 "You are now identified")
+        (with-current-buffer "#chan" ; autojoined
+          (funcall expect 10 "the gallants desire it"))
+        (erc-cmd-QUIT "")
+        (funcall expect 3 "finished")))
+
+    (erc-services-mode -1)))
+
 ;;; erc-scenarios-services-misc.el ends here
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 4d0d69cd7b..578b2641a6 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -428,18 +428,21 @@
 
     (ert-info ("ascii")
       (puthash 'CASEMAPPING  '("ascii") erc--isupport-params)
+      (should (equal (erc-downcase "ABC 123 ΔΞΩΣ") "abc 123 ΔΞΩΣ"))
       (should (equal (erc-downcase "Bob[m]`") "bob[m]`"))
       (should (equal (erc-downcase "Tilde~") "tilde~" ))
       (should (equal (erc-downcase "\\O/") "\\o/" )))
 
     (ert-info ("rfc1459")
       (puthash 'CASEMAPPING  '("rfc1459") erc--isupport-params)
+      (should (equal (erc-downcase "ABC 123 ΔΞΩΣ") "abc 123 ΔΞΩΣ"))
       (should (equal (erc-downcase "Bob[m]`") "bob{m}`" ))
       (should (equal (erc-downcase "Tilde~") "tilde^" ))
       (should (equal (erc-downcase "\\O/") "|o/" )))
 
     (ert-info ("rfc1459-strict")
       (puthash 'CASEMAPPING  '("rfc1459-strict") erc--isupport-params)
+      (should (equal (erc-downcase "ABC 123 ΔΞΩΣ") "abc 123 ΔΞΩΣ"))
       (should (equal (erc-downcase "Bob[m]`") "bob{m}`"))
       (should (equal (erc-downcase "Tilde~") "tilde~" ))
       (should (equal (erc-downcase "\\O/") "|o/" )))))
@@ -1328,7 +1331,7 @@ Some docstring"
 
                       (defun erc-mname-enable (&optional ,arg-en)
                         "Enable ERC mname mode.
-With ARG, do so in all buffers for the current connection."
+When called interactively, do so in all buffers for the current connection."
                         (interactive "p")
                         (when (derived-mode-p 'erc-mode)
                           (if ,arg-en
@@ -1340,7 +1343,7 @@ With ARG, do so in all buffers for the current 
connection."
 
                       (defun erc-mname-disable (&optional ,arg-dis)
                         "Disable ERC mname mode.
-With ARG, do so in all buffers for the current connection."
+When called interactively, do so in all buffers for the current connection."
                         (interactive "p")
                         (when (derived-mode-p 'erc-mode)
                           (if ,arg-dis
diff --git a/test/lisp/erc/resources/base/assoc/queries/netnick.eld 
b/test/lisp/erc/resources/base/assoc/queries/netnick.eld
new file mode 100644
index 0000000000..98dda12690
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/queries/netnick.eld
@@ -0,0 +1,42 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 1 "USER tester 0 * :tester")
+ (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.00 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version ergo-v2.8.0")
+ (0.00 ":irc.foonet.org 003 tester :This server was created Mon, 12 Dec 2022 
01:25:38 UTC")
+ (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 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=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.00 ":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:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :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 1 :channels formed")
+ (0.00 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0.00 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0.01 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0.00 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode 10 "MODE tester +i")
+ (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."))
+
+((join 10 "JOIN #chan")
+ (0.03 ":tester!~u@z5d6jyn8pwxge.irc JOIN #chan"))
+
+((mode-1 10 "MODE #chan")
+ (0.01 ":irc.foonet.org 353 tester = #chan :@alice bob foonet tester")
+ (0.00 ":irc.foonet.org 366 tester #chan :End of NAMES list")
+ (0.03 ":irc.foonet.org 324 tester #chan +nt")
+ (0.00 ":irc.foonet.org 329 tester #chan 1670808354")
+ (0.00 ":bob!~u@d6ftaiqzk8x2k.irc PRIVMSG #chan :tester, welcome!")
+ (0.00 ":alice!~u@d6ftaiqzk8x2k.irc PRIVMSG #chan :tester, welcome!")
+
+ (0.00 ":foonet!~u@z5d6jyn8pwxge.irc PRIVMSG tester :hi")
+
+ (0.03 ":bob!~u@d6ftaiqzk8x2k.irc PRIVMSG #chan :alice: Forbear it therefore; 
give your cause to heaven.")
+ (0.01 ":alice!~u@d6ftaiqzk8x2k.irc PRIVMSG #chan :bob: Even at thy teat thou 
hadst thy tyranny.")
+ (0.00 ":foonet!~u@z5d6jyn8pwxge.irc QUIT :connection closed"))
+
+((quit 10 "QUIT :\2ERC\2")
+ (0.03 ":tester!~u@z5d6jyn8pwxge.irc QUIT :Quit: \2ERC\2"))
diff --git a/test/lisp/erc/resources/base/assoc/queries/non-erc.eld 
b/test/lisp/erc/resources/base/assoc/queries/non-erc.eld
new file mode 100644
index 0000000000..aecd4922c3
--- /dev/null
+++ b/test/lisp/erc/resources/base/assoc/queries/non-erc.eld
@@ -0,0 +1,33 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 1 "USER tester 0 * :tester")
+ (0.00 ":irc.foonet.org 001 tester :Welcome to the foonet IRC Network tester")
+ (0.00 ":irc.foonet.org 002 tester :Your host is irc.foonet.org, running 
version ergo-v2.8.0")
+ (0.00 ":irc.foonet.org 003 tester :This server was created Mon, 12 Dec 2022 
01:25:38 UTC")
+ (0.00 ":irc.foonet.org 004 tester irc.foonet.org ergo-v2.8.0 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=# 
ELIST=U EXCEPTS EXTBAN=,m FORWARD=f INVEX KICKLEN=390 :are supported by this 
server")
+ (0.00 ":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:,WHOIS:1,USERHOST:10,PRIVMSG:4,TAGMSG:4,NOTICE:4,MONITOR:100
 TOPICLEN=390 UTF8MAPPING=rfc8265 UTF8ONLY WHOX :are supported by this server")
+ (0.01 ":irc.foonet.org 005 tester draft/CHATHISTORY=100 :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 1 :channels formed")
+ (0.00 ":irc.foonet.org 255 tester :I have 4 clients and 0 servers")
+ (0.00 ":irc.foonet.org 265 tester 4 4 :Current local users 4, max 4")
+ (0.01 ":irc.foonet.org 266 tester 4 4 :Current global users 4, max 4")
+ (0.00 ":irc.foonet.org 422 tester :MOTD File is missing"))
+
+((mode 10 "MODE tester +i")
+ (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.")
+ (0.00 ":dummy!~u@z5d6jyn8pwxge.irc PRIVMSG tester :hi"))
+
+((~privmsg-open 10 "PRIVMSG nitwit :hola")
+ (0.00 ":nitwit!~u@m5q6wla8cjktr.irc PRIVMSG tester :ciao"))
+
+((privmsg 10 "PRIVMSG dummy :howdy")
+ (0.00 ":dummy!~u@z5d6jyn8pwxge.irc PRIVMSG tester :bye")
+ (0.01 ":dummy!~u@z5d6jyn8pwxge.irc QUIT :connection closed"))
+
+((quit 10 "QUIT :\2ERC\2")
+ (0.03 ":tester!~u@z5d6jyn8pwxge.irc QUIT :Quit: \2ERC\2"))
diff --git a/test/lisp/erc/resources/base/local-modules/fourth.eld 
b/test/lisp/erc/resources/base/local-modules/fourth.eld
index fd6d62b6cc..4ac5dcbd38 100644
--- a/test/lisp/erc/resources/base/local-modules/fourth.eld
+++ b/test/lisp/erc/resources/base/local-modules/fourth.eld
@@ -1,7 +1,7 @@
 ;; -*- mode: lisp-data; -*-
 ((cap 10 "CAP REQ :sasl"))
 ((nick 10 "NICK tester`"))
-((user 10 "USER tester 0 * :tester"))
+((user 10 "USER tester` 0 * :tester"))
 
 ((authenticate 10 "AUTHENTICATE PLAIN")
  (0.0 ":irc.foonet.org CAP * ACK sasl")
diff --git a/test/lisp/erc/resources/erc-d/erc-d-i.el 
b/test/lisp/erc/resources/erc-d/erc-d-i.el
index db113335a8..15a0b16bfd 100644
--- a/test/lisp/erc/resources/erc-d/erc-d-i.el
+++ b/test/lisp/erc/resources/erc-d/erc-d-i.el
@@ -1,22 +1,21 @@
 ;;; erc-d-i.el --- IRC helpers for ERC test server -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/test/lisp/erc/resources/erc-d/erc-d-t.el 
b/test/lisp/erc/resources/erc-d/erc-d-t.el
index a1a7e7e88d..6d68608a4f 100644
--- a/test/lisp/erc/resources/erc-d/erc-d-t.el
+++ b/test/lisp/erc/resources/erc-d/erc-d-t.el
@@ -1,26 +1,24 @@
 ;;; erc-d-t.el --- ERT helpers for ERC test server -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
 
-;;; Commentary:
+;; 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:
+
 (eval-and-compile
   (let* ((d (file-name-directory (or (macroexp-file-name) buffer-file-name)))
          (load-path (cons (directory-file-name d) load-path)))
diff --git a/test/lisp/erc/resources/erc-d/erc-d-tests.el 
b/test/lisp/erc/resources/erc-d/erc-d-tests.el
index 8dd5cef7aa..feddc4c062 100644
--- a/test/lisp/erc/resources/erc-d/erc-d-tests.el
+++ b/test/lisp/erc/resources/erc-d/erc-d-tests.el
@@ -1,26 +1,24 @@
 ;;; erc-d-tests.el --- tests for erc-d -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
 
-;;; Commentary:
+;; 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 (expand-file-name ".." (ert-resource-directory))
diff --git a/test/lisp/erc/resources/erc-d/erc-d-u.el 
b/test/lisp/erc/resources/erc-d/erc-d-u.el
index ce13efef62..60181cdc8b 100644
--- a/test/lisp/erc/resources/erc-d/erc-d-u.el
+++ b/test/lisp/erc/resources/erc-d/erc-d-u.el
@@ -1,22 +1,21 @@
 ;;; erc-d-u.el --- Helpers for ERC test server -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/test/lisp/erc/resources/erc-d/erc-d.el 
b/test/lisp/erc/resources/erc-d/erc-d.el
index d6082227c5..f8704834b9 100644
--- a/test/lisp/erc/resources/erc-d/erc-d.el
+++ b/test/lisp/erc/resources/erc-d/erc-d.el
@@ -1,22 +1,21 @@
 ;;; erc-d.el --- A dumb test server for ERC -*- lexical-binding: t -*-
 
 ;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el 
b/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el
index bb8869dff6..f675f67501 100644
--- a/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el
+++ b/test/lisp/erc/resources/erc-d/resources/proxy-subprocess.el
@@ -1,24 +1,22 @@
 ;;; proxy-subprocess.el --- Example setup file for erc-d  -*- lexical-binding: 
t; -*-
 
 ;; Copyright (C) 2020-2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
-;;; Commentary:
 ;;; Code:
 
 (defvar erc-d-tmpl-vars)
diff --git a/test/lisp/erc/resources/erc-scenarios-common.el 
b/test/lisp/erc/resources/erc-scenarios-common.el
index 601c9e95c8..57d4658e75 100644
--- a/test/lisp/erc/resources/erc-scenarios-common.el
+++ b/test/lisp/erc/resources/erc-scenarios-common.el
@@ -1,22 +1,21 @@
 ;;; erc-scenarios-common.el --- Common helpers for ERC scenarios -*- 
lexical-binding: t -*-
 
 ;; Copyright (C) 2022 Free Software Foundation, Inc.
-;;
+
 ;; This file is part of GNU Emacs.
-;;
-;; This program 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.
-;;
-;; This program 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.
-;;
+
+;; 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 this program.  If not, see
-;; <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
@@ -186,7 +185,7 @@ Dialog resource directories are located by expanding the 
variable
 (defun erc-scenarios-common-assert-initial-buf-name (id port)
   ;; Assert no limbo period when explicit ID given
   (should (string= (if id
-                       (symbol-name id)
+                       (format "%s" id)
                      (format "127.0.0.1:%d" port))
                    (buffer-name))))
 
diff --git a/test/lisp/erc/resources/networks/announced-missing/foonet.eld 
b/test/lisp/erc/resources/networks/announced-missing/foonet.eld
index 79b0fb462a..4481f27663 100644
--- a/test/lisp/erc/resources/networks/announced-missing/foonet.eld
+++ b/test/lisp/erc/resources/networks/announced-missing/foonet.eld
@@ -3,6 +3,3 @@
 ((user 1 "USER user 0 * :tester")
  (0 ":irc.foonet.org 001 tester :Welcome to the FooNet Internet Relay Chat 
Network tester")
  (0 ":irc.foonet.org 422 tester :MOTD File is missing"))
-
-((mode-user 1.2 "MODE tester +i")
- (0 ":tester MODE tester :+Zi"))
diff --git a/test/lisp/erc/resources/services/auth-source/recon.eld 
b/test/lisp/erc/resources/services/auth-source/recon.eld
new file mode 100644
index 0000000000..2ab52c9bec
--- /dev/null
+++ b/test/lisp/erc/resources/services/auth-source/recon.eld
@@ -0,0 +1,48 @@
+;; -*- mode: lisp-data; -*-
+((nick 10 "NICK tester"))
+((user 5 "USER tester 0 * :tester")
+ (0.00 ":irc.foonet.net NOTICE * :*** Looking up your hostname...")
+ (0.04 ":irc.foonet.net NOTICE tester :*** Could not resolve your hostname: 
Domain not found; using your IP address (10.0.2.100) instead.")
+ (0.06 ":irc.foonet.net 001 tester :Welcome to the FooNet IRC Network 
tester!tester@10.0.2.100")
+ (0.01 ":irc.foonet.net 002 tester :Your host is irc.foonet.net, running 
version InspIRCd-3")
+ (0.01 ":irc.foonet.net 003 tester :This server was created 08:32:24 Dec 05 
2022")
+ (0.01 ":irc.foonet.net 004 tester irc.foonet.net InspIRCd-3 BIRcgikorsw 
ACHIKMORTXabcefghijklmnopqrstvz :HIXabefghjkloqv")
+ (0.01 ":irc.foonet.net 005 tester ACCEPT=30 AWAYLEN=200 BOT=B CALLERID=g 
CASEMAPPING=ascii CHANLIMIT=#:20 CHANMODES=IXbeg,k,Hfjl,ACKMORTcimnprstz 
CHANNELLEN=64 CHANTYPES=# ELIST=CMNTU ESILENCE=CcdiNnPpTtx EXCEPTS=e :are 
supported by this server")
+ (0.01 ":irc.foonet.net 005 tester EXTBAN=,ACORTUacjrwz HOSTLEN=64 INVEX=I 
KEYLEN=32 KICKLEN=255 LINELEN=512 MAXLIST=I:100,X:100,b:100,e:100,g:100 
MAXTARGETS=20 MODES=20 MONITOR=30 NAMELEN=128 NAMESX NETWORK=FooNet :are 
supported by this server")
+ (0.01 ":irc.foonet.net 005 tester NICKLEN=30 PREFIX=(qaohv)~&@%+ SAFELIST 
SILENCE=32 STATUSMSG=~&@%+ TOPICLEN=307 UHNAMES USERIP USERLEN=10 
USERMODES=,,s,BIRcgikorw WHOX :are supported by this server")
+ (0.01 ":irc.foonet.net 251 tester :There are 2 users and 0 invisible on 2 
servers")
+ (0.00 ":irc.foonet.net 253 tester 1 :unknown connections")
+ (0.00 ":irc.foonet.net 254 tester 1 :channels formed")
+ (0.00 ":irc.foonet.net 255 tester :I have 2 clients and 1 servers")
+ (0.00 ":irc.foonet.net 265 tester :Current local users: 2  Max: 3")
+ (0.00 ":irc.foonet.net 266 tester :Current global users: 2  Max: 3")
+ (0.00 ":irc.foonet.net 375 tester :irc.foonet.net message of the day")
+ (0.00 ":irc.foonet.net 372 tester :Have fun!")
+ (0.00 ":irc.foonet.net 376 tester :End of message of the day."))
+
+((mode-a 10 "MODE tester +i")
+ (0.00 ":irc.foonet.net 501 tester x :is not a recognized user mode.")
+ (0.04 ":tester!tester@10.0.2.100 MODE tester :+i")
+ (0.00 ":NickServ!NickServ@services.int NOTICE tester :This nickname is 
registered. Please choose a different nickname, or identify via \2/msg NickServ 
identify <password>\2."))
+
+((~privmsg 10 "PRIVMSG NickServ :IDENTIFY changeme")
+ (0.00 ":NickServ!NickServ@services.int NOTICE tester :You are now identified 
for \2tester\2.")
+ (0.01 ":irc.foonet.net 900 tester tester!tester@10.0.2.100 tester :You are 
now logged in as tester"))
+
+((~join 10 "JOIN #chan")
+ (0.00 ":tester!tester@10.0.2.100 JOIN :#chan")
+ (0.04 ":irc.foonet.net 353 tester = #chan :@alice bob tester")
+ (0.00 ":irc.foonet.net 366 tester #chan :End of /NAMES list."))
+
+((mode-b 10 "MODE #chan")
+ (0.03 ":irc.foonet.net 324 tester #chan :+nt")
+ (0.01 ":irc.foonet.net 329 tester #chan :1670229160")
+ (0.00 ":alice!alice@0::1 PRIVMSG #chan :tester, welcome!")
+ (0.00 ":bob!bob@0::1 PRIVMSG #chan :tester, welcome!")
+ (0.05 ":alice!alice@0::1 PRIVMSG #chan :bob: Thou art the cap of all the 
fools alive.")
+ (0.06 ":bob!bob@0::1 PRIVMSG #chan :alice: What, man! 'tis a night of revels; 
the gallants desire it."))
+
+((quit 10 "QUIT :\2ERC\2")
+ (0.1 ":tester!tester@10.0.2.100 QUIT :Client Quit"))
+
+((drop 1 DROP))
diff --git a/test/lisp/eshell/em-alias-tests.el 
b/test/lisp/eshell/em-alias-tests.el
index aca622220e..0a26e8d201 100644
--- a/test/lisp/eshell/em-alias-tests.el
+++ b/test/lisp/eshell/em-alias-tests.el
@@ -72,6 +72,15 @@
    (eshell-match-command-output "show-all-args a" "a\n")
    (eshell-match-command-output "show-all-args a b c" "a\nb\nc\n")))
 
+(ert-deftest em-alias-test/alias-all-args-var-splice ()
+  "Test alias with splicing the $* variable"
+  (with-temp-eshell
+   (eshell-insert-command "alias show-all-args 'echo args: $@*'")
+   (eshell-match-command-output "show-all-args" "args:\n")
+   (eshell-match-command-output "show-all-args a" "(\"args:\" \"a\")\n")
+   (eshell-match-command-output "show-all-args a b c"
+                                "(\"args:\" \"a\" \"b\" \"c\")\n")))
+
 (ert-deftest em-alias-test/alias-all-args-var-indices ()
   "Test alias with the $* variable using indices"
   (with-temp-eshell
diff --git a/test/lisp/eshell/esh-arg-tests.el 
b/test/lisp/eshell/esh-arg-tests.el
new file mode 100644
index 0000000000..77f9404d4c
--- /dev/null
+++ b/test/lisp/eshell/esh-arg-tests.el
@@ -0,0 +1,105 @@
+;;; esh-arg-tests.el --- esh-arg test suite  -*- lexical-binding:t -*-
+
+;; Copyright (C) 2022 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/>.
+
+;;; Commentary:
+
+;; Tests for Eshell's argument handling.
+
+;;; Code:
+
+(require 'ert)
+(require 'esh-mode)
+(require 'eshell)
+
+(require 'eshell-tests-helpers
+         (expand-file-name "eshell-tests-helpers"
+                           (file-name-directory (or load-file-name
+                                                    default-directory))))
+
+(defvar eshell-test-value nil)
+
+;;; Tests:
+
+(ert-deftest esh-arg-test/escape/nonspecial ()
+  "Test that \"\\c\" and \"c\" are equivalent when \"c\" is not a
+special character."
+  (with-temp-eshell
+   (eshell-match-command-output "echo he\\llo"
+                                "hello\n")))
+
+(ert-deftest esh-arg-test/escape/nonspecial-unicode ()
+  "Test that \"\\c\" and \"c\" are equivalent when \"c\" is a
+unicode character (unicode characters are nonspecial by
+definition)."
+  (with-temp-eshell
+   (eshell-match-command-output "echo Vid\\éos"
+                                "Vidéos\n")))
+
+(ert-deftest esh-arg-test/escape/special ()
+  "Test that the backslash is not preserved for escaped special
+chars."
+  (with-temp-eshell
+   (eshell-match-command-output "echo he\\\\llo"
+                                ;; Backslashes are doubled for regexp.
+                                "he\\\\llo\n")))
+
+(ert-deftest esh-arg-test/escape/newline ()
+  "Test that an escaped newline is equivalent to the empty string.
+When newlines are *nonspecial*, an escaped newline should be
+treated as just a newline."
+  (with-temp-eshell
+   (eshell-match-command-output "echo hi\\\nthere"
+                                "hithere\n")))
+
+(ert-deftest esh-arg-test/escape/newline-conditional ()
+  "Test invocation of an if/else statement using line continuations."
+  (let ((eshell-test-value t))
+    (eshell-command-result-equal
+     "if $eshell-test-value \\\n{echo yes} \\\n{echo no}"
+     "yes"))
+  (let ((eshell-test-value nil))
+    (eshell-command-result-equal
+     "if $eshell-test-value \\\n{echo yes} \\\n{echo no}"
+     "no")))
+
+(ert-deftest esh-arg-test/escape-quoted/nonspecial ()
+  "Test that the backslash is preserved for escaped nonspecial
+chars."
+  (with-temp-eshell
+   (eshell-match-command-output "echo \"h\\i\""
+                                ;; Backslashes are doubled for regexp.
+                                "h\\\\i\n")))
+
+(ert-deftest esh-arg-test/escape-quoted/special ()
+  "Test that the backslash is not preserved for escaped special
+chars."
+  (with-temp-eshell
+   (eshell-match-command-output "echo \"\\\"hi\\\\\""
+                                ;; Backslashes are doubled for regexp.
+                                "\\\"hi\\\\\n")))
+
+(ert-deftest esh-arg-test/escape-quoted/newline ()
+  "Test that an escaped newline is equivalent to the empty string.
+When newlines are *nonspecial*, an escaped newline should be
+treated literally, as a backslash and a newline."
+  (with-temp-eshell
+   (eshell-match-command-output "echo \"hi\\\nthere\""
+                                "hithere\n")))
+
+;; esh-arg-tests.el ends here
diff --git a/test/lisp/eshell/esh-var-tests.el 
b/test/lisp/eshell/esh-var-tests.el
index 96fde026a5..d95669fdaf 100644
--- a/test/lisp/eshell/esh-var-tests.el
+++ b/test/lisp/eshell/esh-var-tests.el
@@ -60,6 +60,18 @@
   (eshell-command-result-equal "echo $\"user-login-name\"-foo"
                                (concat user-login-name "-foo")))
 
+(ert-deftest esh-var-test/interp-list-var ()
+  "Interpolate list variable"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo $eshell-test-value"
+                                 '(1 2 3))))
+
+(ert-deftest esh-var-test/interp-list-var-concat ()
+  "Interpolate and concat list variable"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo a$'eshell-test-value'z"
+                                 '("a1" 2 "3z"))))
+
 (ert-deftest esh-var-test/interp-var-indices ()
   "Interpolate list variable with indices"
   (let ((eshell-test-value '("zero" "one" "two" "three" "four")))
@@ -131,6 +143,26 @@
     (eshell-command-result-equal "echo $#eshell-test-value" 1)
     (eshell-command-result-equal "echo $#eshell-test-value[foo]" 3)))
 
+(ert-deftest esh-var-test/interp-var-splice ()
+  "Splice-interpolate list variable"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo a $@eshell-test-value z"
+                                 '("a" 1 2 3 "z"))))
+
+(ert-deftest esh-var-test/interp-var-splice-concat ()
+  "Splice-interpolate and concat list variable"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo it is a$@'eshell-test-value'z"
+                                 '("it" "is" "a1" 2 "3z"))
+    ;; This is a tricky case.  We're concatenating a spliced list and
+    ;; a non-spliced list.  The general rule is that splicing should
+    ;; work as though the user typed "$X[0] $X[1] ... $X[N]".  That
+    ;; means that the last value of our splice should get concatenated
+    ;; into the first value of the non-spliced list.
+    (eshell-command-result-equal
+     "echo it is $@'eshell-test-value'$eshell-test-value"
+     '("it" "is" 1 2 (31 2 3)))))
+
 (ert-deftest esh-var-test/interp-lisp ()
   "Interpolate Lisp form evaluation"
   (eshell-command-result-equal "+ $(+ 1 2) 3" 6))
@@ -197,6 +229,9 @@
    (eshell-match-command-output "echo ${echo hi}-${*echo there}"
                                 "hi-there\n")))
 
+
+;; Quoted variable interpolation
+
 (ert-deftest esh-var-test/quoted-interp-var ()
   "Interpolate variable inside double-quotes"
   (eshell-command-result-equal "echo \"$user-login-name\""
@@ -209,6 +244,18 @@
   (eshell-command-result-equal "echo \"hi, $\\\"user-login-name\\\"\""
                                (concat "hi, " user-login-name)))
 
+(ert-deftest esh-var-test/quoted-interp-list-var ()
+  "Interpolate list variable inside double-quotes"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo \"$eshell-test-value\""
+                                 "(1 2 3)")))
+
+(ert-deftest esh-var-test/quoted-interp-list-var-concat ()
+  "Interpolate and concat list variable inside double-quotes"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo \"a$'eshell-test-value'z\""
+                                 "a(1 2 3)z")))
+
 (ert-deftest esh-var-test/quoted-interp-var-indices ()
   "Interpolate string variable with indices inside double-quotes"
   (let ((eshell-test-value '("zero" "one" "two" "three" "four")))
@@ -291,6 +338,18 @@ inside double-quotes"
     (eshell-command-result-equal "echo \"$#eshell-test-value[foo]\""
                                  "3")))
 
+(ert-deftest esh-var-test/quoted-interp-var-splice ()
+  "Splice-interpolate list variable inside double-quotes"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo a \"$@eshell-test-value\" z"
+                                 '("a" "1 2 3" "z"))))
+
+(ert-deftest esh-var-test/quoted-interp-var-splice-concat ()
+  "Splice-interpolate and concat list variable inside double-quotes"
+  (let ((eshell-test-value '(1 2 3)))
+    (eshell-command-result-equal "echo \"a$@'eshell-test-value'z\""
+                                 "a1 2 3z")))
+
 (ert-deftest esh-var-test/quoted-interp-lisp ()
   "Interpolate Lisp form evaluation inside double-quotes"
   (eshell-command-result-equal "echo \"hi $(concat \\\"the\\\" \\\"re\\\")\""
@@ -325,6 +384,21 @@ inside double-quotes"
                                "foo\nbar baz"))
 
 
+;; Interpolating commands
+
+(ert-deftest esh-var-test/command-interp ()
+  "Interpolate a variable as a command name"
+  (let ((eshell-test-value "printnl"))
+    (eshell-command-result-equal "$eshell-test-value hello there"
+                                 "hello\nthere\n")))
+
+(ert-deftest esh-var-test/command-interp-splice ()
+  "Interpolate a splice variable as a command name with arguments"
+  (let ((eshell-test-value '("printnl" "hello" "there")))
+    (eshell-command-result-equal "$@eshell-test-value"
+                                 "hello\nthere\n")))
+
+
 ;; Interpolated variable conversion
 
 (ert-deftest esh-var-test/interp-convert-var-number ()
diff --git a/test/lisp/eshell/eshell-tests.el b/test/lisp/eshell/eshell-tests.el
index d5112146c2..c67ac67fd3 100644
--- a/test/lisp/eshell/eshell-tests.el
+++ b/test/lisp/eshell/eshell-tests.el
@@ -105,37 +105,6 @@
      (format template "format \"%s\" eshell-in-pipeline-p")
      "nil")))
 
-(ert-deftest eshell-test/escape-nonspecial ()
-  "Test that \"\\c\" and \"c\" are equivalent when \"c\" is not a
-special character."
-  (with-temp-eshell
-   (eshell-match-command-output "echo he\\llo"
-                                "hello\n")))
-
-(ert-deftest eshell-test/escape-nonspecial-unicode ()
-  "Test that \"\\c\" and \"c\" are equivalent when \"c\" is a
-unicode character (unicode characters are nonspecial by
-definition)."
-  (with-temp-eshell
-   (eshell-match-command-output "echo Vid\\éos"
-                                "Vidéos\n")))
-
-(ert-deftest eshell-test/escape-nonspecial-quoted ()
-  "Test that the backslash is preserved for escaped nonspecial
-chars"
-  (with-temp-eshell
-   (eshell-match-command-output "echo \"h\\i\""
-                                ;; Backslashes are doubled for regexp.
-                                "h\\\\i\n")))
-
-(ert-deftest eshell-test/escape-special-quoted ()
-  "Test that the backslash is not preserved for escaped special
-chars"
-  (with-temp-eshell
-   (eshell-match-command-output "echo \"\\\"hi\\\\\""
-                                ;; Backslashes are doubled for regexp.
-                                "\\\"hi\\\\\n")))
-
 (ert-deftest eshell-test/command-running-p ()
   "Modeline should show no command running"
   (with-temp-eshell
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index 682b5cdb44..011bfa67cc 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -1038,17 +1038,6 @@ unquoted file names."
     (let ((default-directory nospecial-dir))
       (should-error (make-directory "dir")))))
 
-(ert-deftest files-tests-file-name-non-special-make-directory-internal ()
-  (files-tests--with-temp-non-special (tmpdir nospecial-dir t)
-    (let ((default-directory nospecial-dir))
-      (make-directory-internal "dir")
-      (should (file-directory-p "dir"))
-      (delete-directory "dir")))
-  (files-tests--with-temp-non-special-and-file-name-handler
-      (tmpdir nospecial-dir t)
-    (let ((default-directory nospecial-dir))
-      (should-error (make-directory-internal "dir")))))
-
 (ert-deftest files-tests-file-name-non-special-make-nearby-temp-file ()
   (let* ((default-directory (file-name-quote temporary-file-directory))
          (near-tmpfile (make-nearby-temp-file "file")))
@@ -1272,11 +1261,11 @@ works as expected if the default directory is quoted."
            (a/b (concat dirname "a/b")))
       (write-region "" nil file)
       (should-error (make-directory "/"))
-      (should-not (make-directory "/" t))
+      (should (make-directory "/" t))
       (should-error (make-directory dir))
-      (should-not (make-directory dir t))
+      (should (make-directory dir t))
       (should-error (make-directory dirname))
-      (should-not (make-directory dirname t))
+      (should (make-directory dirname t))
       (should-error (make-directory file))
       (should-error (make-directory file t))
       (should-not (make-directory subdir1))
@@ -1357,7 +1346,9 @@ name (Bug#28412)."
            (dest (concat dirname "dest/new/directory/"))
            (file (concat (file-name-as-directory source) "file"))
            (source2 (concat dirname "source2"))
-           (dest2 (concat dirname "dest/new2")))
+           (dest2 (concat dirname "dest/new2"))
+           (source3 (concat dirname "source3/d"))
+           (dest3 (concat dirname "dest3/d")))
       (make-directory source)
       (write-region "" nil file)
       (copy-directory source dest t t t)
@@ -1365,6 +1356,11 @@ name (Bug#28412)."
       (make-directory (concat (file-name-as-directory source2) "a") t)
       (copy-directory source2 dest2)
       (should (file-directory-p (concat (file-name-as-directory dest2) "a")))
+      (make-directory source3 t)
+      (write-region "x\n" nil (concat (file-name-as-directory source3) "file"))
+      (make-directory dest3 t)
+      (write-region "y\n" nil (concat (file-name-as-directory dest3) "file"))
+      (copy-directory source3 (file-name-directory dest3) t)
       (delete-directory dir 'recursive))))
 
 (ert-deftest files-tests-abbreviate-file-name-homedir ()
diff --git a/test/lisp/gnus/mml-sec-tests.el b/test/lisp/gnus/mml-sec-tests.el
index e4e607b70e..f8ebf2f3a9 100644
--- a/test/lisp/gnus/mml-sec-tests.el
+++ b/test/lisp/gnus/mml-sec-tests.el
@@ -789,7 +789,7 @@ With Ma Gnus v0.14 and earlier a signature would be created 
with a wrong key."
 
 ;; TODO Passphrase passing and caching in Emacs does not seem to work
 ;; with gpgsm at all.
-;; Independently of caching settings, a pinentry dialogue is displayed.
+;; Independently of caching settings, a pinentry dialog is displayed.
 ;; Thus, the following tests require the user to enter the correct gpgsm
 ;; passphrases at the correct points in time.  (Either empty string or
 ;; "Passphrase".)
diff --git a/test/lisp/international/ucs-normalize-tests.el 
b/test/lisp/international/ucs-normalize-tests.el
index 8d7ac5eb8b..380140308a 100644
--- a/test/lisp/international/ucs-normalize-tests.el
+++ b/test/lisp/international/ucs-normalize-tests.el
@@ -255,7 +255,8 @@ Must be called with `ucs-normalize-tests--norm-buf' as 
current buffer."
 
 (ert-deftest ucs-normalize-part1 ()
   :tags '(:expensive-test)
-  (skip-unless (not (getenv "EMACS_HYDRA_CI"))) ; SLOW ~ 1800s
+  (skip-unless (not (or (getenv "EMACS_HYDRA_CI")
+                        (getenv "EMACS_EMBA_CI")))) ; SLOW ~ 1800s
   ;; This takes a long time, so make sure we're compiled.
   (dolist (fun '(ucs-normalize-tests--part1-rule2
                  ucs-normalize-tests--rule1-failing-for-partX
diff --git a/test/lisp/loadhist-resources/loadhist--bar.el 
b/test/lisp/loadhist-resources/loadhist--bar.el
index 5c8914ed57..94e82c1b18 100644
--- a/test/lisp/loadhist-resources/loadhist--bar.el
+++ b/test/lisp/loadhist-resources/loadhist--bar.el
@@ -4,18 +4,20 @@
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Code:
 
diff --git a/test/lisp/loadhist-resources/loadhist--foo.el 
b/test/lisp/loadhist-resources/loadhist--foo.el
index 3574c22013..8d48c3683d 100644
--- a/test/lisp/loadhist-resources/loadhist--foo.el
+++ b/test/lisp/loadhist-resources/loadhist--foo.el
@@ -4,18 +4,20 @@
 
 ;; Author: Stefan Monnier <monnier@iro.umontreal.ca>
 
-;; This program is free software; you can redistribute it and/or modify
+;; 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.
 
-;; This program is distributed in the hope that it will be useful,
+;; 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 this program.  If not, see <https://www.gnu.org/licenses/>.
+;; along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.
 
 ;;; Commentary:
 
diff --git a/test/lisp/proced-tests.el b/test/lisp/proced-tests.el
new file mode 100644
index 0000000000..3c1f5493e7
--- /dev/null
+++ b/test/lisp/proced-tests.el
@@ -0,0 +1,105 @@
+;;; proced-tests.el --- Test suite for proced.el -*- lexical-binding: t -*-
+
+;; Copyright (C) 2022 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)
+(require 'proced)
+(require 'thingatpt)
+
+(cl-defmacro proced--within-buffer (format filter &body body)
+  "Execute BODY within a proced buffer using format FORMAT and filter FILTER."
+  `(let ((proced-format ,format)
+         (proced-filter ,filter)
+         (proced-auto-update-flag nil)
+         (inhibit-message t))
+     (proced)
+     (unwind-protect
+         (with-current-buffer "*Proced*"
+           ,@body)
+       (kill-buffer "*Proced*"))))
+
+(defun proced--assert-emacs-pid-in-buffer ()
+  "Fail unless the process ID of the current Emacs process exists in buffer."
+  (should (string-match-p
+           (number-to-string (emacs-pid))
+           (buffer-substring-no-properties (point-min) (point-max)))))
+
+(defun proced--move-to-column (attribute)
+  "Move to the column under ATTRIBUTE in the current proced buffer."
+  (move-to-column (string-match attribute proced-header-line)))
+
+(ert-deftest proced-format-test ()
+  (dolist (format '(short medium long verbose))
+    (proced--within-buffer
+     format
+     'user
+     (proced--assert-emacs-pid-in-buffer))))
+
+(ert-deftest proced-update-test ()
+  (proced--within-buffer
+   'short
+   'user
+   (proced-update)
+   (proced--assert-emacs-pid-in-buffer)))
+
+(ert-deftest proced-revert-test ()
+  (proced--within-buffer
+   'short
+   'user
+   (proced-revert)
+   (proced--assert-emacs-pid-in-buffer)))
+
+(ert-deftest proced-color-test ()
+  (let ((proced-enable-color-flag t))
+    (proced--within-buffer
+     'short
+     'user
+     (proced--assert-emacs-pid-in-buffer))))
+
+(ert-deftest proced-refine-test ()
+  ;;(skip-unless (memq system-type '(gnu/linux gnu/kfreebsd darwin)))
+  (proced--within-buffer
+   'medium
+   'user
+   ;; When refining on PID for process A, a process is kept if and only
+   ;; if its PID are the same as process A, which more or less guarentees
+   ;; the refinement will remove some processes.
+   (proced--move-to-column "PID")
+   (let ((pid (word-at-point)))
+     (proced-refine)
+     (while (not (eobp))
+       (proced--move-to-column "PID")
+       (should (string= pid (word-at-point)))
+       (forward-line)))))
+
+(ert-deftest proced-refine-with-update-test ()
+  (proced--within-buffer
+   'medium
+   'user
+   (proced--move-to-column "PID")
+   (let ((pid (word-at-point)))
+     (proced-refine)
+     (proced-update t)
+     (while (not (eobp))
+       (proced--move-to-column "PID")
+       (should (string= pid (word-at-point)))
+       (forward-line)))))
+
+(provide 'proced-tests)
+;;; proced-tests.el ends here
diff --git a/test/lisp/progmodes/eglot-tests.el 
b/test/lisp/progmodes/eglot-tests.el
new file mode 100644
index 0000000000..d8c9560f5b
--- /dev/null
+++ b/test/lisp/progmodes/eglot-tests.el
@@ -0,0 +1,1320 @@
+;;; eglot-tests.el --- Tests for eglot.el            -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2018-2022 Free Software Foundation, Inc.
+
+;; Author: João Távora <joaotavora@gmail.com>
+;; Keywords: tests
+
+;; 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:
+
+;; Tests for lisp/progmodes/eglot.el
+;;
+;; Many of these tests rely on the availability of third-party LSP
+;; servers.  They are automatically skipped if the program is not
+;; available.
+;;
+;; Some of these tests rely on the GNU ELPA package company.el and
+;; yasnippet.el being available.
+
+;; Some of the tests require access to a remote host files.  Since
+;; this could be problematic, a mock-up connection method "mock" is
+;; used.  Emulating a remote connection, it simply calls "sh -i".
+;; Tramp's file name handlers still run, so this test is sufficient
+;; except for connection establishing.
+
+;; If you want to test a real Tramp connection, set
+;; $REMOTE_TEMPORARY_FILE_DIRECTORY to a suitable value in order to
+;; overwrite the default value.  If you want to skip tests accessing a
+;; remote host, set this environment variable to "/dev/null" or
+;; whatever is appropriate on your system.
+
+;;; Code:
+(require 'eglot)
+(require 'cl-lib)
+(require 'ert)
+(require 'tramp) ; must be prior ert-x
+(require 'ert-x) ; ert-simulate-command
+(require 'edebug)
+(require 'python) ; some tests use pylsp
+(require 'cc-mode) ; c-mode-hook
+(require 'company nil t)
+(require 'yasnippet nil t)
+(require 'subr-x)
+(require 'flymake) ; project-diagnostics
+
+;;; Helpers
+
+(defmacro eglot--with-fixture (fixture &rest body)
+  "Setup FIXTURE, call BODY, teardown FIXTURE.
+FIXTURE is a list.  Its elements are of the form (FILE . CONTENT)
+to create a readable FILE with CONTENT.  FILE may be a directory
+name and CONTENT another (FILE . CONTENT) list to specify a
+directory hierarchy.  FIXTURE's elements can also be (SYMBOL
+VALUE) meaning SYMBOL should be bound to VALUE during BODY and
+then restored."
+  (declare (indent 1) (debug t))
+  `(eglot--call-with-fixture
+    ,fixture #'(lambda () ,@body)))
+
+(defun eglot--make-file-or-dir (ass)
+  (let ((file-or-dir-name (car ass))
+        (content (cdr ass)))
+    (cond ((listp content)
+           (make-directory file-or-dir-name 'parents)
+           (let ((default-directory (concat default-directory "/" 
file-or-dir-name)))
+             (mapcan #'eglot--make-file-or-dir content)))
+          ((stringp content)
+           (with-temp-buffer
+             (insert content)
+             (write-region nil nil file-or-dir-name nil 'nomessage))
+           (list (expand-file-name file-or-dir-name)))
+          (t
+           (eglot--error "Expected a string or a directory spec")))))
+
+(defun eglot--call-with-fixture (fixture fn)
+  "Helper for `eglot--with-fixture'.  Run FN under FIXTURE."
+  (let* ((fixture-directory (make-nearby-temp-file "eglot--fixture" t))
+         (default-directory fixture-directory)
+         file-specs created-files
+         syms-to-restore
+         new-servers
+         test-body-successful-p)
+    (dolist (spec fixture)
+      (cond ((symbolp spec)
+             (push (cons spec (symbol-value spec)) syms-to-restore)
+             (set spec nil))
+            ((symbolp (car spec))
+             (push (cons (car spec) (symbol-value (car spec))) syms-to-restore)
+             (set (car spec) (cadr spec)))
+            ((stringp (car spec)) (push spec file-specs))))
+    (unwind-protect
+        (let* ((home (getenv "HOME"))
+               (process-environment
+                (append
+                 `(;; Set XDF_CONFIG_HOME to /dev/null to prevent
+                   ;; user-configuration to have an influence on
+                   ;; language servers. (See github#441)
+                   "XDG_CONFIG_HOME=/dev/null"
+                   ;; ... on the flip-side, a similar technique by
+                   ;; Emacs's test makefiles means that HOME is set to
+                   ;; /nonexistent.  This breaks some common
+                   ;; installations for LSP servers like pylsp, making
+                   ;; these tests mostly useless, so we hack around it
+                   ;; here with a great big hack.
+                   ,(format "HOME=%s"
+                            (if (file-exists-p home) home
+                              (format "/home/%s" (getenv "USER")))))
+                 process-environment))
+               ;; Prevent "Can't guess python-indent-offset ..." messages.
+               (python-indent-guess-indent-offset-verbose . nil)
+               (eglot-server-initialized-hook
+                (lambda (server) (push server new-servers))))
+          (setq created-files (mapcan #'eglot--make-file-or-dir file-specs))
+          (prog1 (funcall fn)
+            (setq test-body-successful-p t)))
+      (eglot--message
+       "Test body was %s" (if test-body-successful-p "OK" "A FAILURE"))
+      (unwind-protect
+          (let ((eglot-autoreconnect nil))
+            (dolist (server new-servers)
+              (when (jsonrpc-running-p server)
+                (condition-case oops
+                    (eglot-shutdown
+                     server nil 3 (not test-body-successful-p))
+                  (error
+                   (eglot--message "Non-critical shutdown error after test: %S"
+                                   oops))))
+              (when (not test-body-successful-p)
+                ;; We want to do this after the sockets have
+                ;; shut down such that any pending data has been
+                ;; consumed and is available in the process
+                ;; buffers.
+                (let ((buffers (delq nil (list
+                                          ;; FIXME: Accessing "internal" 
symbol here.
+                                          (process-buffer (jsonrpc--process 
server))
+                                          (jsonrpc-stderr-buffer server)
+                                          (jsonrpc-events-buffer server)))))
+                  (cond (noninteractive
+                         (dolist (buffer buffers)
+                           (eglot--message "%s:" (buffer-name buffer))
+                           (princ (with-current-buffer buffer (buffer-string))
+                                  'external-debugging-output)))
+                        (t
+                         (eglot--message "Preserved for inspection: %s"
+                                         (mapconcat #'buffer-name buffers ", 
"))))))))
+        (eglot--cleanup-after-test fixture-directory created-files 
syms-to-restore)))))
+
+(defun eglot--cleanup-after-test (fixture-directory created-files 
syms-to-restore)
+  (let ((buffers-to-delete
+         (delete nil (mapcar #'find-buffer-visiting created-files))))
+    (eglot--message "Killing %s, wiping %s, restoring %s"
+                    buffers-to-delete
+                    fixture-directory
+                    (mapcar #'car syms-to-restore))
+    (cl-loop for (sym . val) in syms-to-restore
+             do (set sym val))
+    (dolist (buf buffers-to-delete) ;; have to save otherwise will get prompted
+      (with-current-buffer buf (save-buffer) (kill-buffer)))
+    (delete-directory fixture-directory 'recursive)
+    ;; Delete Tramp buffers if needed.
+    (when (file-remote-p temporary-file-directory)
+      (tramp-cleanup-connection
+       (tramp-dissect-file-name temporary-file-directory) nil 
'keep-password))))
+
+(cl-defmacro eglot--with-timeout (timeout &body body)
+  (declare (indent 1) (debug t))
+  `(eglot--call-with-timeout ,timeout (lambda () ,@body)))
+
+(defun eglot--call-with-timeout (timeout fn)
+  (let* ((tag (gensym "eglot-test-timeout"))
+         (timed-out (make-symbol "timeout"))
+         (timeout-and-message
+          (if (listp timeout) timeout
+            (list timeout "waiting for test to finish")))
+         (timeout (car timeout-and-message))
+         (message (cadr timeout-and-message))
+         (timer)
+         (retval))
+    (unwind-protect
+        (setq retval
+              (catch tag
+                (setq timer
+                      (run-with-timer timeout nil
+                                      (lambda ()
+                                        (unless edebug-active
+                                          (throw tag timed-out)))))
+                (funcall fn)))
+      (cancel-timer timer)
+      (when (eq retval timed-out)
+        (error "%s" (concat "Timed out " message))))))
+
+(defun eglot--find-file-noselect (file &optional noerror)
+  (unless (or noerror
+              (file-readable-p file)) (error "%s does not exist" file))
+  (find-file-noselect file))
+
+(cl-defmacro eglot--sniffing ((&key server-requests
+                                    server-notifications
+                                    server-replies
+                                    client-requests
+                                    client-notifications
+                                    client-replies)
+                              &rest body)
+  "Run BODY saving LSP JSON messages in variables, most recent first."
+  (declare (indent 1) (debug (sexp &rest form)))
+  (let ((log-event-ad-sym (make-symbol "eglot--event-sniff")))
+    `(unwind-protect
+         (let ,(delq nil (list server-requests
+                               server-notifications
+                               server-replies
+                               client-requests
+                               client-notifications
+                               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)))))))))
+            '((name . ,log-event-ad-sym)))
+           ,@body)
+       (advice-remove #'jsonrpc--log-event ',log-event-ad-sym))))
+
+(cl-defmacro eglot--wait-for ((events-sym &optional (timeout 1) message) args 
&body body)
+  "Spin until FN match in EVENTS-SYM, flush events after it.
+Pass TIMEOUT to `eglot--with-timeout'."
+  (declare (indent 2) (debug (sexp sexp sexp &rest form)))
+  `(eglot--with-timeout '(,timeout ,(or message
+                                        (format "waiting for:\n%s" 
(pp-to-string body))))
+     (let ((event
+            (cl-loop thereis (cl-loop for json in ,events-sym
+                                      for method = (plist-get json :method)
+                                      when (keywordp method)
+                                      do (plist-put json :method
+                                                    (substring
+                                                     (symbol-name method)
+                                                     1))
+                                      when (funcall
+                                            (jsonrpc-lambda ,args ,@body) json)
+                                      return (cons json before)
+                                      collect json into before)
+                     for i from 0
+                     when (zerop (mod i 5))
+                     ;; do (eglot--message "still struggling to find in %s"
+                     ;;                    ,events-sym)
+                     do
+                     ;; `read-event' is essential to have the file
+                     ;; watchers come through.
+                     (read-event "[eglot] Waiting a bit..." nil 0.1)
+                     (accept-process-output nil 0.1))))
+       (setq ,events-sym (cdr event))
+       (eglot--message "Event detected:\n%s"
+                       (pp-to-string (car event))))))
+
+;; `rust-mode' is not a part of Emacs, so we define these two shims
+;; which should be more than enough for testing.
+(unless (functionp 'rust-mode)
+  (define-derived-mode rust-mode prog-mode "Rust")
+  (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode)))
+
+;; `typescript-mode' is not a part of Emacs, so we define these two
+;; shims which should be more than enough for testing.
+(unless (functionp 'typescript-mode)
+  (define-derived-mode typescript-mode prog-mode "TypeScript")
+  (add-to-list 'auto-mode-alist '("\\.ts\\'" . typescript-mode)))
+
+(defun eglot--tests-connect (&optional timeout)
+  (let* ((timeout (or timeout 10))
+         (eglot-sync-connect t)
+         (eglot-connect-timeout timeout))
+    (apply #'eglot--connect (eglot--guess-contact))))
+
+(defun eglot--simulate-key-event (char)
+  "Like (execute-kbd-macro (vector char)), but with `call-interactively'."
+  ;; Also, this is a bit similar to what electric-tests.el does.
+  (setq last-input-event char)
+  (setq last-command-event char)
+  (call-interactively (key-binding (vector char))))
+
+
+;;; Unit tests
+
+(ert-deftest eglot-test-eclipse-connect ()
+  "Connect to eclipse.jdt.ls server."
+  (skip-unless (executable-find "jdtls"))
+  (eglot--with-fixture
+      '(("project/src/main/java/foo" . (("Main.java" . "")))
+        ("project/.git/" . nil))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/src/main/java/foo/Main.java")
+      (eglot--sniffing (:server-notifications s-notifs)
+        (should (eglot--tests-connect 20))
+        (eglot--wait-for (s-notifs 10)
+            (&key _id method &allow-other-keys)
+          (string= method "language/status"))))))
+
+(defun eglot-tests--auto-detect-running-server-1 ()
+  (let (server)
+    (eglot--with-fixture
+     `(("project" . (("coiso.c" . "bla")
+                     ("merdix.c" . "bla")))
+       ("anotherproject" . (("cena.c" . "bla"))))
+     (with-current-buffer
+         (eglot--find-file-noselect "project/coiso.c")
+       (should (setq server (eglot--tests-connect)))
+       (should (eglot-current-server)))
+     (with-current-buffer
+         (eglot--find-file-noselect "project/merdix.c")
+       (should (eglot-current-server))
+       (should (eq (eglot-current-server) server)))
+     (with-current-buffer
+         (eglot--find-file-noselect "anotherproject/cena.c")
+       (should-error (eglot--current-server-or-lose))))))
+
+(ert-deftest eglot-test-auto-detect-running-server ()
+  "Visit a file and \\[eglot], then visit a neighbor."
+  (skip-unless (executable-find "clangd"))
+  (eglot-tests--auto-detect-running-server-1))
+
+(ert-deftest eglot-test-auto-shutdown ()
+  "Visit a file and \\[eglot], then kill buffer."
+  (skip-unless (executable-find "clangd"))
+  (let (server
+        buffer)
+    (eglot--with-fixture
+        `(("project" . (("thingy.c" . "int main() {return 0;}"))))
+      (with-current-buffer
+          (setq buffer (eglot--find-file-noselect "project/thingy.c"))
+        (should (setq server (eglot--tests-connect)))
+        (should (eglot-current-server))
+        (let ((eglot-autoshutdown nil)) (kill-buffer buffer))
+        (should (jsonrpc-running-p server))
+        ;; re-find file...
+        (setq buffer (eglot--find-file-noselect (buffer-file-name buffer)))
+        ;; ;; but now kill it with `eglot-autoshutdown' set to t
+        (let ((eglot-autoshutdown t)) (kill-buffer buffer))
+        (should (not (jsonrpc-running-p server)))))))
+
+(ert-deftest eglot-test-auto-reconnect ()
+  "Start a server.  Kill it.  Watch it reconnect."
+  (skip-unless (executable-find "clangd"))
+  (let (server (eglot-autoreconnect 1))
+    (eglot--with-fixture
+        `(("project" . (("thingy.c" . "bla")
+                        ("thingy2.c" . "bla"))))
+      (with-current-buffer
+          (eglot--find-file-noselect "project/thingy.c")
+        (should (setq server (eglot--tests-connect)))
+        ;; In 1.2 seconds > `eglot-autoreconnect' kill servers. We
+        ;; should have a automatic reconnection.
+        (run-with-timer 1.2 nil (lambda () (delete-process
+                                            (jsonrpc--process server))))
+        (while (jsonrpc-running-p server) (accept-process-output nil 0.5))
+        (should (eglot-current-server))
+        ;; Now try again too quickly
+        (setq server (eglot-current-server))
+        (let ((proc (jsonrpc--process server)))
+          (run-with-timer 0.5 nil (lambda () (delete-process proc)))
+          (while (process-live-p proc) (accept-process-output nil 0.5)))
+        (should (not (eglot-current-server)))))))
+
+(ert-deftest eglot-test-rust-analyzer-watches-files ()
+  "Start rust-analyzer.  Notify it when a critical file changes."
+  (skip-unless (executable-find "rust-analyzer"))
+  (skip-unless (executable-find "cargo"))
+  (let ((eglot-autoreconnect 1))
+    (eglot--with-fixture
+        '(("watch-project" . (("coiso.rs" . "bla")
+                              ("merdix.rs" . "bla"))))
+      (with-current-buffer
+          (eglot--find-file-noselect "watch-project/coiso.rs")
+        (should (zerop (shell-command "cargo init")))
+        (eglot--sniffing (
+                          :server-requests s-requests
+                          :client-notifications c-notifs
+                          :client-replies c-replies
+                          )
+          (should (eglot--tests-connect))
+          (let (register-id)
+            (eglot--wait-for (s-requests 1)
+                (&key id method &allow-other-keys)
+              (setq register-id id)
+              (string= method "client/registerCapability"))
+            (eglot--wait-for (c-replies 1)
+                (&key id error &allow-other-keys)
+              (and (eq id register-id) (null error))))
+          (delete-file "Cargo.toml")
+          (eglot--wait-for
+              (c-notifs 3 "waiting for didChangeWatchedFiles notification")
+              (&key method params &allow-other-keys)
+            (and (string= method "workspace/didChangeWatchedFiles")
+                 (cl-destructuring-bind (&key uri type)
+                     (elt (plist-get params :changes) 0)
+                   (and (string= (eglot--path-to-uri "Cargo.toml") uri)
+                        (= type 3))))))))))
+
+(ert-deftest eglot-test-basic-diagnostics ()
+  "Test basic diagnostics."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("diag-project" .
+         (("main.c" . "int main(){froat a = 42.2; return 0;}"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "diag-project/main.c")
+      (eglot--sniffing (:server-notifications s-notifs)
+        (eglot--tests-connect)
+        (eglot--wait-for (s-notifs 2)
+            (&key _id method &allow-other-keys)
+          (string= method "textDocument/publishDiagnostics"))
+        (flymake-start)
+        (goto-char (point-min))
+        (flymake-goto-next-error 1 '() t)
+        (should (eq 'flymake-error (face-at-point)))))))
+
+(ert-deftest eglot-test-diagnostic-tags-unnecessary-code ()
+  "Test rendering of diagnostics tagged \"unnecessary\"."
+  (skip-unless (executable-find "rust-analyzer"))
+  (skip-unless (executable-find "cargo"))
+  (eglot--with-fixture
+      '(("diagnostic-tag-project" .
+         (("main.rs" .
+           "fn main() -> () { let test=3; }"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "diagnostic-tag-project/main.rs")
+      (let ((eglot-server-programs '((rust-mode . ("rust-analyzer")))))
+        (should (zerop (shell-command "cargo init")))
+        (eglot--sniffing (:server-notifications s-notifs)
+          (eglot--tests-connect)
+          (eglot--wait-for (s-notifs 10)
+              (&key _id method &allow-other-keys)
+            (string= method "textDocument/publishDiagnostics"))
+          (flymake-start)
+          (goto-char (point-min))
+          (flymake-goto-next-error 1 '() t)
+          (should (eq 'eglot-diagnostic-tag-unnecessary-face 
(face-at-point))))))))
+
+(defun eglot--eldoc-on-demand ()
+  ;; Trick Eldoc 1.1.0 into accepting on-demand calls.
+  (eldoc t))
+
+(defun eglot--tests-force-full-eldoc ()
+  ;; FIXME: This uses some Eldoc implementation defatils.
+  (when (buffer-live-p eldoc--doc-buffer)
+    (with-current-buffer eldoc--doc-buffer
+      (let ((inhibit-read-only t))
+        (erase-buffer))))
+  (eglot--eldoc-on-demand)
+  (cl-loop
+   repeat 10
+   for retval = (and (buffer-live-p eldoc--doc-buffer)
+                     (with-current-buffer eldoc--doc-buffer
+                       (let ((bs (buffer-string)))
+                         (unless (zerop (length bs)) bs))))
+   when retval return retval
+   do (sit-for 0.5)
+   finally (error "eglot--tests-force-full-eldoc didn't deliver")))
+
+(ert-deftest eglot-test-rust-analyzer-hover-after-edit ()
+  "Hover and highlightChanges."
+  (skip-unless (executable-find "rust-analyzer"))
+  (skip-unless (executable-find "cargo"))
+  (eglot--with-fixture
+      '(("hover-project" .
+         (("main.rs" .
+           "fn test() -> i32 { let test=3; return te; }"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "hover-project/main.rs")
+      (should (zerop (shell-command "cargo init")))
+      (eglot--sniffing (
+                        :server-replies s-replies
+                        :client-requests c-reqs
+                        )
+        (eglot--tests-connect)
+        (goto-char (point-min))
+        (search-forward "return te")
+        (insert "st")
+        (progn
+          ;; simulate these two which don't happen when buffer isn't
+          ;; visible in a window.
+          (eglot--signal-textDocument/didChange)
+          (eglot--eldoc-on-demand))
+        (let (pending-id)
+          (eglot--wait-for (c-reqs 2)
+              (&key id method &allow-other-keys)
+            (setq pending-id id)
+            (string= method "textDocument/documentHighlight"))
+          (eglot--wait-for (s-replies 2)
+              (&key id &allow-other-keys)
+            (eq id pending-id)))))))
+
+(ert-deftest eglot-test-rename-a-symbol ()
+  "Test basic symbol renaming."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("rename-project"
+         . (("main.c" .
+             "int foo() {return 42;} int main() {return foo();}"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "rename-project/main.c")
+      (eglot--tests-connect)
+      (goto-char (point-min)) (search-forward "foo")
+      (eglot-rename "bar")
+      (should (equal (buffer-string)
+                     "int bar() {return 42;} int main() {return bar();}")))))
+
+(ert-deftest eglot-test-basic-completions ()
+  "Test basic autocompletion in a python LSP."
+  (skip-unless (executable-find "pylsp"))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . "import sys\nsys.exi"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (should (eglot--tests-connect))
+      (goto-char (point-max))
+      (completion-at-point)
+      (should (looking-back "sys.exit")))))
+
+(ert-deftest eglot-test-non-unique-completions ()
+  "Test completion resulting in 'Complete, but not unique'."
+  (skip-unless (executable-find "pylsp"))
+  (eglot--with-fixture
+      '(("project" . (("something.py" . "foo=1\nfoobar=2\nfoo"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (should (eglot--tests-connect))
+      (goto-char (point-max))
+      (completion-at-point))
+    ;; FIXME: `current-message' doesn't work here :-(
+    (with-current-buffer (messages-buffer)
+      (save-excursion
+        (goto-char (point-max))
+        (forward-line -1)
+        (should (looking-at "Complete, but not unique"))))))
+
+(ert-deftest eglot-test-basic-xref ()
+  "Test basic xref functionality in a python LSP."
+  (skip-unless (executable-find "pylsp"))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . "def foo(): pass\ndef bar(): foo()"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (should (eglot--tests-connect))
+      (search-forward "bar(): f")
+      (call-interactively 'xref-find-definitions)
+      (should (looking-at "foo(): pass")))))
+
+(defvar eglot--test-python-buffer
+  "\
+def foobarquux(a, b, c=True): pass
+def foobazquuz(d, e, f): pass
+")
+
+(declare-function yas-minor-mode nil)
+
+(ert-deftest eglot-test-snippet-completions ()
+  "Test simple snippet completion in a python LSP."
+  (skip-unless (and (executable-find "pylsp")
+                    (functionp 'yas-minor-mode)))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . ,eglot--test-python-buffer))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (yas-minor-mode 1)
+      (let ((eglot-workspace-configuration
+             `((:pylsp . (:plugins (:jedi_completion (:include_params t)))))))
+        (should (eglot--tests-connect)))
+      (goto-char (point-max))
+      (insert "foobar")
+      (completion-at-point)
+      (should (looking-back "foobarquux("))
+      (should (looking-at "a, b)")))))
+
+(defvar company-candidates)
+(declare-function company-mode nil)
+(declare-function company-complete nil)
+
+(ert-deftest eglot-test-snippet-completions-with-company ()
+  "Test simple snippet completion in a python LSP."
+  (skip-unless (and (executable-find "pylsp")
+                    (functionp 'yas-minor-mode)
+                    (functionp 'company-complete)))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . ,eglot--test-python-buffer))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (yas-minor-mode 1)
+      (let ((eglot-workspace-configuration
+             `((:pylsp . (:plugins (:jedi_completion (:include_params t)))))))
+        (should (eglot--tests-connect)))
+      (goto-char (point-max))
+      (insert "foo")
+      (company-mode)
+      (company-complete)
+      (should (looking-back "fooba"))
+      (should (= 2 (length company-candidates)))
+      ;; this last one is brittle, since there it is possible that
+      ;; pylsp will change the representation of this candidate
+      (should (member "foobazquuz(d, e, f)" company-candidates)))))
+
+(ert-deftest eglot-test-eldoc-after-completions ()
+  "Test documentation echo in a python LSP."
+  (skip-unless (executable-find "pylsp"))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . "import sys\nsys.exi"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (should (eglot--tests-connect))
+      (goto-char (point-max))
+      (completion-at-point)
+      (should (looking-back "sys.exit"))
+      (should (string-match "^exit" (eglot--tests-force-full-eldoc))))))
+
+(ert-deftest eglot-test-multiline-eldoc ()
+  "Test if suitable amount of lines of hover info are shown."
+  (skip-unless (executable-find "pylsp"))
+  (eglot--with-fixture
+      `(("project" . (("hover-first.py" . "from datetime import datetime"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/hover-first.py")
+      (should (eglot--tests-connect))
+      (goto-char (point-max))
+      ;; one-line
+      (let* ((eldoc-echo-area-use-multiline-p t)
+             (captured-message (eglot--tests-force-full-eldoc)))
+        (should (string-match "datetim" captured-message))
+        (should (cl-find ?\n captured-message))))))
+
+(ert-deftest eglot-test-single-line-eldoc ()
+  "Test if suitable amount of lines of hover info are shown."
+  (skip-unless (executable-find "pylsp"))
+  (eglot--with-fixture
+      `(("project" . (("hover-first.py" . "from datetime import datetime"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/hover-first.py")
+      (should (eglot--tests-connect))
+      (goto-char (point-max))
+      ;; one-line
+      (let* ((eldoc-echo-area-use-multiline-p nil)
+             (captured-message (eglot--tests-force-full-eldoc)))
+        (should (string-match "datetim" captured-message))
+        (should (not (cl-find ?\n eldoc-last-message)))))))
+
+(ert-deftest eglot-test-python-autopep-formatting ()
+  "Test formatting in the pylsp python LSP.
+pylsp prefers autopep over yafp, despite its README stating the contrary."
+  ;; Beware, default autopep rules can change over time, which may
+  ;; affect this test.
+  (skip-unless (and (executable-find "pylsp")
+                    (executable-find "autopep8")))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . "def a():pass\n\ndef b():pass"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (should (eglot--tests-connect))
+      ;; Try to format just the second line
+      (search-forward "b():pa")
+      (eglot-format (line-beginning-position) (line-end-position))
+      (should (looking-at "ss"))
+      (should
+       (or (string= (buffer-string) "def a():pass\n\n\ndef b(): pass\n")
+           ;; autopep8 2.0.0 (pycodestyle: 2.9.1)
+           (string= (buffer-string) "def a():pass\n\ndef b(): pass")))
+      ;; now format the whole buffer
+      (eglot-format-buffer)
+      (should
+       (string= (buffer-string) "def a(): pass\n\n\ndef b(): pass\n")))))
+
+(ert-deftest eglot-test-python-yapf-formatting ()
+  "Test formatting in the pylsp python LSP."
+  (skip-unless (and (executable-find "pylsp")
+                    (not (executable-find "autopep8"))
+                    (or (executable-find "yapf")
+                        (executable-find "yapf3"))))
+  (eglot--with-fixture
+      `(("project" . (("something.py" . "def a():pass\ndef b():pass"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.py")
+      (should (eglot--tests-connect))
+      ;; Try to format just the second line
+      (search-forward "b():pa")
+      (eglot-format (line-beginning-position) (line-end-position))
+      (should (looking-at "ss"))
+      (should
+       (string= (buffer-string) "def a():pass\n\n\ndef b():\n    pass\n"))
+      ;; now format the whole buffer
+      (eglot-format-buffer)
+      (should
+       (string= (buffer-string) "def a():\n    pass\n\n\ndef b():\n    
pass\n")))))
+
+(ert-deftest eglot-test-rust-on-type-formatting ()
+  "Test textDocument/onTypeFormatting against rust-analyzer."
+  (skip-unless (executable-find "rust-analyzer"))
+  (skip-unless (executable-find "cargo"))
+  (eglot--with-fixture
+      '(("on-type-formatting-project" .
+         (("main.rs" .
+           "fn main() -> () {\n  foo\n    .bar()\n  "))))
+    (with-current-buffer
+        (eglot--find-file-noselect "on-type-formatting-project/main.rs")
+      (let ((eglot-server-programs '((rust-mode . ("rust-analyzer")))))
+        (should (zerop (shell-command "cargo init")))
+        (eglot--sniffing (:server-notifications s-notifs)
+          (should (eglot--tests-connect))
+          (eglot--wait-for (s-notifs 10) (&key method &allow-other-keys)
+             (string= method "textDocument/publishDiagnostics")))
+        (goto-char (point-max))
+        (eglot--simulate-key-event ?.)
+        (should (looking-back "^    \\."))))))
+
+(ert-deftest eglot-test-javascript-basic ()
+  "Test basic autocompletion in a JavaScript LSP."
+  (skip-unless (and (executable-find "typescript-language-server")
+                    (executable-find "tsserver")))
+  (eglot--with-fixture
+      '(("project" . (("hello.js" . "console.log('Hello world!');"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/hello.js")
+      (let ((eglot-server-programs
+             '((js-mode . ("typescript-language-server" "--stdio")))))
+        (goto-char (point-max))
+        (eglot--sniffing (:server-notifications
+                          s-notifs
+                          :client-notifications
+                          c-notifs)
+          (should (eglot--tests-connect))
+          (eglot--wait-for (s-notifs 2) (&key method &allow-other-keys)
+            (string= method "textDocument/publishDiagnostics"))
+          (should (not (eq 'flymake-error (face-at-point))))
+          (insert "{")
+          (eglot--signal-textDocument/didChange)
+          (eglot--wait-for (c-notifs 1) (&key method &allow-other-keys)
+            (string= method "textDocument/didChange"))
+          (eglot--wait-for (s-notifs 2) (&key params method &allow-other-keys)
+            (and (string= method "textDocument/publishDiagnostics")
+                 (cl-destructuring-bind (&key _uri diagnostics) params
+                   (cl-find-if (jsonrpc-lambda (&key severity 
&allow-other-keys)
+                                 (= severity 1))
+                               diagnostics)))))))))
+
+(ert-deftest eglot-test-project-wide-diagnostics-typescript ()
+  "Test diagnostics through multiple files in a TypeScript LSP."
+  (skip-unless (and (executable-find "typescript-language-server")
+                    (executable-find "tsserver")))
+  (eglot--with-fixture
+      '(("project" . (("hello.ts" . "const thing = 5;\nexport { thin }")
+                      ("hello2.ts" . "import { thing } from './hello'"))))
+    (eglot--make-file-or-dir '(".git"))
+    (let ((eglot-server-programs
+           '((typescript-mode . ("typescript-language-server" "--stdio")))))
+      ;; Check both files because typescript-language-server doesn't
+      ;; report all errors on startup, at least not with such a simple
+      ;; setup.
+      (with-current-buffer (eglot--find-file-noselect "project/hello2.ts")
+        (eglot--sniffing (:server-notifications s-notifs)
+          (eglot--tests-connect)
+          (flymake-start)
+          (eglot--wait-for (s-notifs 10)
+              (&key _id method &allow-other-keys)
+            (string= method "textDocument/publishDiagnostics"))
+          (should (= 2 (length (flymake--project-diagnostics)))))
+        (with-current-buffer (eglot--find-file-noselect "hello.ts")
+          (eglot--sniffing (:server-notifications s-notifs)
+            (flymake-start)
+            (eglot--wait-for (s-notifs 10)
+                (&key _id method &allow-other-keys)
+              (string= method "textDocument/publishDiagnostics"))
+            (should (= 4 (length (flymake--project-diagnostics))))))))))
+
+(ert-deftest eglot-test-project-wide-diagnostics-rust-analyzer ()
+  "Test diagnostics through multiple files in a TypeScript LSP."
+  (skip-unless (executable-find "rust-analyzer"))
+  (skip-unless (executable-find "cargo"))
+  (eglot--with-fixture
+      '(("project" .
+         (("main.rs" .
+           "fn main() -> () { let test=3; }")
+          ("other-file.rs" .
+           "fn foo() -> () { let hi=3; }"))))
+    (eglot--make-file-or-dir '(".git"))
+    (let ((eglot-server-programs '((rust-mode . ("rust-analyzer")))))
+      ;; Open other-file, and see diagnostics arrive for main.rs
+      (with-current-buffer (eglot--find-file-noselect "project/other-file.rs")
+        (should (zerop (shell-command "cargo init")))
+        (eglot--sniffing (:server-notifications s-notifs)
+          (eglot--tests-connect)
+          (flymake-start)
+          (eglot--wait-for (s-notifs 10)
+              (&key _id method &allow-other-keys)
+            (string= method "textDocument/publishDiagnostics"))
+          (let ((diags (flymake--project-diagnostics)))
+            (should (= 2 (length diags)))
+            ;; Check that we really get a diagnostic from main.rs, and
+            ;; not from other-file.rs
+            (should (string-suffix-p
+                     "main.rs"
+                     (flymake-diagnostic-buffer (car diags))))))))))
+
+(ert-deftest eglot-test-json-basic ()
+  "Test basic autocompletion in vscode-json-languageserver."
+  (skip-unless (executable-find "vscode-json-languageserver"))
+  (eglot--with-fixture
+      '(("project" .
+         (("p.json" . "{\"foo.b")
+          ("s.json" . "{\"properties\":{\"foo.bar\":{\"default\":\"fb\"}}}")
+          (".git" . nil))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/p.json")
+      (yas-minor-mode)
+      (goto-char 2)
+      (insert "\"$schema\": \"file://"
+              (file-name-directory buffer-file-name) "s.json\",")
+      (let ((eglot-server-programs
+             '((js-mode . ("vscode-json-languageserver" "--stdio")))))
+        (goto-char (point-max))
+        (should (eglot--tests-connect))
+        (completion-at-point)
+        (should (looking-back "\"foo.bar\": \""))
+        (should (looking-at "fb\"$"))))))
+
+(defun eglot-tests--lsp-abiding-column-1 ()
+  (eglot--with-fixture
+      '(("project" .
+         (("foo.c" . "const char write_data[] = 
u8\"🚂🚃🚄🚅🚆🚈🚇🚈🚉🚊🚋🚌🚎🚝🚞🚟🚠🚡🛤🛲\";"))))
+    (let ((eglot-server-programs
+           '((c-mode . ("clangd")))))
+      (with-current-buffer
+          (eglot--find-file-noselect "project/foo.c")
+        (setq-local eglot-move-to-column-function 
#'eglot-move-to-lsp-abiding-column)
+        (setq-local eglot-current-column-function #'eglot-lsp-abiding-column)
+        (eglot--sniffing (:client-notifications c-notifs)
+          (eglot--tests-connect)
+          (end-of-line)
+          (insert "p ")
+          (eglot--signal-textDocument/didChange)
+          (eglot--wait-for (c-notifs 2) (&key params &allow-other-keys)
+            (should (equal 71 (cadddr (cadadr (aref (cadddr params) 0))))))
+          (beginning-of-line)
+          (should (eq eglot-move-to-column-function 
#'eglot-move-to-lsp-abiding-column))
+          (funcall eglot-move-to-column-function 71)
+          (should (looking-at "p")))))))
+
+(ert-deftest eglot-test-lsp-abiding-column ()
+  "Test basic `eglot-lsp-abiding-column' and 
`eglot-move-to-lsp-abiding-column'."
+  (skip-unless (executable-find "clangd"))
+  (eglot-tests--lsp-abiding-column-1))
+
+(ert-deftest eglot-test-ensure ()
+  "Test basic `eglot-ensure' functionality."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("project" . (("foo.c" . "int foo() {return 42;}")
+                      ("bar.c" . "int bar() {return 42;}")))
+        (c-mode-hook (eglot-ensure)))
+    (let (server)
+      ;; need `ert-simulate-command' because `eglot-ensure'
+      ;; relies on `post-command-hook'.
+      (with-current-buffer
+          (ert-simulate-command
+           '(find-file "project/foo.c"))
+        ;; FIXME: This test fails without this sleep on my machine.
+        ;; Figure out why and solve this more cleanly.
+        (sleep-for 0.1)
+        (should (setq server (eglot-current-server))))
+      (with-current-buffer
+          (ert-simulate-command
+           '(find-file "project/bar.c"))
+        (should (eq server (eglot-current-server)))))))
+
+(ert-deftest eglot-test-slow-sync-connection-wait ()
+  "Connect with `eglot-sync-connect' set to t."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("project" . (("something.c" . "int foo() {return 42;}"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.c")
+      (let ((eglot-sync-connect t)
+            (eglot-server-programs
+             `((c-mode . ("sh" "-c" "sleep 1 && clangd")))))
+        (should (eglot--tests-connect 3))))))
+
+(ert-deftest eglot-test-slow-sync-connection-intime ()
+  "Connect synchronously with `eglot-sync-connect' set to 2."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("project" . (("something.c" . "int foo() {return 42;}"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.c")
+      (let ((eglot-sync-connect 2)
+            (eglot-server-programs
+             `((c-mode . ("sh" "-c" "sleep 1 && clangd")))))
+        (should (eglot--tests-connect 3))))))
+
+(ert-deftest eglot-test-slow-async-connection ()
+  "Connect asynchronously with `eglot-sync-connect' set to 2."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("project" . (("something.c" . "int foo() {return 42;}"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.c")
+      (let ((eglot-sync-connect 1)
+            (eglot-server-programs
+             `((c-mode . ("sh" "-c" "sleep 2 && clangd")))))
+        (should-not (apply #'eglot--connect (eglot--guess-contact)))
+        (eglot--with-timeout 3
+          (while (not (eglot-current-server))
+            (accept-process-output nil 0.2))
+          (should (eglot-current-server)))))))
+
+(ert-deftest eglot-test-slow-sync-timeout ()
+  "Failed attempt at connection synchronously."
+  (skip-unless (executable-find "clangd"))
+  (eglot--with-fixture
+      `(("project" . (("something.c" . "int foo() {return 42;}"))))
+    (with-current-buffer
+        (eglot--find-file-noselect "project/something.c")
+      (let ((eglot-sync-connect t)
+            (eglot-connect-timeout 1)
+            (eglot-server-programs
+             `((c-mode . ("sh" "-c" "sleep 2 && clangd")))))
+        (should-error (apply #'eglot--connect (eglot--guess-contact)))))))
+
+(ert-deftest eglot-test-capabilities ()
+  "Unit test for `eglot--server-capable'."
+  (cl-letf (((symbol-function 'eglot--capabilities)
+             (lambda (_dummy)
+               ;; test data lifted from Golangserver example at
+               ;; https://github.com/joaotavora/eglot/pull/74
+               (list :textDocumentSync 2 :hoverProvider t
+                     :completionProvider '(:triggerCharacters ["."])
+                     :signatureHelpProvider '(:triggerCharacters ["(" ","])
+                     :definitionProvider t :typeDefinitionProvider t
+                     :referencesProvider t :documentSymbolProvider t
+                     :workspaceSymbolProvider t :implementationProvider t
+                     :documentFormattingProvider t 
:xworkspaceReferencesProvider t
+                     :xdefinitionProvider t :xworkspaceSymbolByProperties t)))
+            ((symbol-function 'eglot--current-server-or-lose)
+             (lambda () nil)))
+    (should (eql 2 (eglot--server-capable :textDocumentSync)))
+    (should (eglot--server-capable :completionProvider :triggerCharacters))
+    (should (equal '(:triggerCharacters ["."]) (eglot--server-capable 
:completionProvider)))
+    (should-not (eglot--server-capable :foobarbaz))
+    (should-not (eglot--server-capable :textDocumentSync :foobarbaz))))
+
+(defmacro eglot--without-interface-warnings (&rest body)
+  (let ((eglot-strict-mode nil))
+    (macroexpand-all (macroexp-progn body) macroexpand-all-environment)))
+
+(ert-deftest eglot-test-strict-interfaces ()
+  (let ((eglot--lsp-interface-alist
+         `((FooObject . ((:foo :bar) (:baz))))))
+    (eglot--without-interface-warnings
+     (should
+      (equal '("foo" . "bar")
+             (let ((eglot-strict-mode nil))
+               (eglot--dbind (foo bar) `(:foo "foo" :bar "bar")
+                 (cons foo bar)))))
+     (should-error
+      (let ((eglot-strict-mode '(disallow-non-standard-keys)))
+        (eglot--dbind (foo bar) `(:foo "foo" :bar "bar" :fotrix bargh)
+          (cons foo bar))))
+     (should
+      (equal '("foo" . "bar")
+             (let ((eglot-strict-mode nil))
+               (eglot--dbind (foo bar) `(:foo "foo" :bar "bar" :fotrix bargh)
+                 (cons foo bar)))))
+     (should-error
+      (let ((eglot-strict-mode '(disallow-non-standard-keys)))
+        (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :bar "bar" :fotrix 
bargh)
+          (cons foo bar))))
+     (should
+      (equal '("foo" . "bar")
+             (let ((eglot-strict-mode '(disallow-non-standard-keys)))
+               (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :bar "bar" 
:baz bargh)
+                 (cons foo bar)))))
+     (should
+      (equal '("foo" . nil)
+             (let ((eglot-strict-mode nil))
+               (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :baz bargh)
+                 (cons foo bar)))))
+     (should
+      (equal '("foo" . "bar")
+             (let ((eglot-strict-mode '(enforce-required-keys)))
+               (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :bar "bar" 
:baz bargh)
+                 (cons foo bar)))))
+     (should-error
+      (let ((eglot-strict-mode '(enforce-required-keys)))
+        (eglot--dbind ((FooObject) foo bar) `(:foo "foo" :baz bargh)
+          (cons foo bar)))))))
+
+(ert-deftest eglot-test-dcase ()
+  (eglot--without-interface-warnings
+   (let ((eglot--lsp-interface-alist
+          `((FooObject . ((:foo :bar) (:baz)))
+            (CodeAction (:title) (:kind :diagnostics :edit :command))
+            (Command ((:title . string) (:command . string)) (:arguments)))))
+     (should
+      (equal
+       "foo"
+       (eglot--dcase `(:foo "foo" :bar "bar")
+         (((FooObject) foo)
+          foo))))
+     (should
+      (equal
+       (list "foo" '(:title "hey" :command "ho") "some edit")
+       (eglot--dcase '(:title "foo"
+                              :command (:title "hey" :command "ho")
+                              :edit "some edit")
+         (((Command) _title _command _arguments)
+          (ert-fail "Shouldn't have destructured this object as a Command"))
+         (((CodeAction) title edit command)
+          (list title command edit)))))
+     (should
+      (equal
+       (list "foo" "some command" nil)
+       (eglot--dcase '(:title "foo" :command "some command")
+         (((Command) title command arguments)
+          (list title command arguments))
+         (((CodeAction) _title _edit _command)
+          (ert-fail "Shouldn't have destructured this object as a 
CodeAction"))))))))
+
+(ert-deftest eglot-test-dcase-issue-452 ()
+  (let ((eglot--lsp-interface-alist
+         `((FooObject . ((:foo :bar) (:baz)))
+           (CodeAction (:title) (:kind :diagnostics :edit :command))
+           (Command ((string . :title) (:command . string)) (:arguments)))))
+    (should
+     (equal
+      (list "foo" '(:command "cmd" :title "alsofoo"))
+      (eglot--dcase '(:title "foo" :command (:command "cmd" :title "alsofoo"))
+        (((Command) _title _command _arguments)
+         (ert-fail "Shouldn't have destructured this object as a Command"))
+        (((CodeAction) title command)
+         (list title command)))))))
+
+(cl-defmacro eglot--guessing-contact ((interactive-sym
+                                       prompt-args-sym
+                                       guessed-class-sym guessed-contact-sym
+                                       &optional guessed-lang-id-sym)
+                                      &body body)
+  "Guess LSP contact with `eglot--guessing-contact', evaluate BODY.
+
+BODY is evaluated twice, with INTERACTIVE bound to the boolean passed to
+`eglot--guess-contact' each time.
+
+If the user would have been prompted, PROMPT-ARGS-SYM is bound to
+the list of arguments that would have been passed to
+`read-shell-command', else nil.  GUESSED-CLASS-SYM,
+GUESSED-CONTACT-SYM and GUESSED-LANG-ID-SYM are bound to the
+useful return values of `eglot--guess-contact'.  Unless the
+server program evaluates to \"a-missing-executable.exe\", this
+macro will assume it exists."
+  (declare (indent 1) (debug t))
+  (let ((i-sym (cl-gensym)))
+    `(dolist (,i-sym '(nil t))
+       (let ((,interactive-sym ,i-sym)
+             (buffer-file-name "_")
+             ,@(when prompt-args-sym `((,prompt-args-sym nil))))
+         (cl-letf (((symbol-function 'executable-find)
+                    (lambda (name &optional _remote)
+                      (unless (string-equal name "a-missing-executable.exe")
+                        (format "/totally-mock-bin/%s" name))))
+                   ((symbol-function 'read-shell-command)
+                    ,(if prompt-args-sym
+                         `(lambda (&rest args) (setq ,prompt-args-sym args) "")
+                       `(lambda (&rest _dummy) ""))))
+           (cl-destructuring-bind
+               (_ _ ,guessed-class-sym ,guessed-contact-sym
+                  ,(or guessed-lang-id-sym '_))
+               (eglot--guess-contact ,i-sym)
+             ,@body))))))
+
+(ert-deftest eglot-test-server-programs-simple-executable ()
+  (let ((eglot-server-programs '((foo-mode "some-executable")))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("some-executable"))))))
+
+(ert-deftest eglot-test-server-programs-simple-missing-executable ()
+  (let ((eglot-server-programs '((foo-mode "a-missing-executable.exe")))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (interactive-p prompt-args guessed-class 
guessed-contact)
+      (should (equal (not prompt-args) (not interactive-p)))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (or prompt-args
+                  (equal guessed-contact '("a-missing-executable.exe")))))))
+
+(ert-deftest eglot-test-server-programs-executable-multiple-major-modes ()
+  (let ((eglot-server-programs '(((bar-mode foo-mode) "some-executable")))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("some-executable"))))))
+
+(ert-deftest eglot-test-server-programs-executable-with-arg ()
+  (let ((eglot-server-programs '((foo-mode "some-executable" "arg1")))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("some-executable" "arg1"))))))
+
+(ert-deftest eglot-test-server-programs-executable-with-args-and-autoport ()
+  (let ((eglot-server-programs '((foo-mode "some-executable" "arg1"
+                                           :autoport "arg2")))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("some-executable" "arg1"
+                                       :autoport "arg2"))))))
+
+(ert-deftest eglot-test-server-programs-host-and-port ()
+  (let ((eglot-server-programs '((foo-mode "somehost.example.com" 7777)))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("somehost.example.com" 7777))))))
+
+(ert-deftest eglot-test-server-programs-host-and-port-and-tcp-args ()
+  (let ((eglot-server-programs '((foo-mode "somehost.example.com" 7777
+                                           :type network)))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("somehost.example.com" 7777
+                                       :type network))))))
+
+(ert-deftest eglot-test-server-programs-class-name-and-plist ()
+  (let ((eglot-server-programs '((foo-mode bar-class :init-key init-val)))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'bar-class))
+      (should (equal guessed-contact '(:init-key init-val))))))
+
+(ert-deftest eglot-test-server-programs-class-name-and-contact-spec ()
+  (let ((eglot-server-programs '((foo-mode bar-class "some-executable" "arg1"
+                                           :autoport "arg2")))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'bar-class))
+      (should (equal guessed-contact '("some-executable" "arg1"
+                                       :autoport "arg2"))))))
+
+(ert-deftest eglot-test-server-programs-function ()
+  (let ((eglot-server-programs '((foo-mode . (lambda (&optional _)
+                                               '("some-executable")))))
+        (major-mode 'foo-mode))
+    (eglot--guessing-contact (_ prompt-args guessed-class guessed-contact)
+      (should (not prompt-args))
+      (should (equal guessed-class 'eglot-lsp-server))
+      (should (equal guessed-contact '("some-executable"))))))
+
+(ert-deftest eglot-test-server-programs-guess-lang ()
+  (let ((major-mode 'foo-mode))
+    (let ((eglot-server-programs '((foo-mode . ("prog-executable")))))
+      (eglot--guessing-contact (_ nil _ _ guessed-lang)
+        (should (equal guessed-lang "foo"))))
+    (let ((eglot-server-programs '(((foo-mode :language-id "bar")
+                                    . ("prog-executable")))))
+      (eglot--guessing-contact (_ nil _ _ guessed-lang)
+        (should (equal guessed-lang "bar"))))
+    (let ((eglot-server-programs '(((baz-mode (foo-mode :language-id "bar"))
+                                    . ("prog-executable")))))
+      (eglot--guessing-contact (_ nil _ _ guessed-lang)
+        (should (equal guessed-lang "bar"))))))
+
+(defun eglot--glob-match (glob str)
+  (funcall (eglot--glob-compile glob t t) str))
+
+(ert-deftest eglot-test-glob-test ()
+  (should (eglot--glob-match "foo/**/baz" "foo/bar/baz"))
+  (should (eglot--glob-match "foo/**/baz" "foo/baz"))
+  (should-not (eglot--glob-match "foo/**/baz" "foo/bar"))
+  (should (eglot--glob-match "foo/**/baz/**/quuz" "foo/baz/foo/quuz"))
+  (should (eglot--glob-match "foo/**/baz/**/quuz" "foo/foo/foo/baz/foo/quuz"))
+  (should-not (eglot--glob-match "foo/**/baz/**/quuz" 
"foo/foo/foo/ding/foo/quuz"))
+  (should (eglot--glob-match "*.js" "foo.js"))
+  (should-not (eglot--glob-match "*.js" "foo.jsx"))
+  (should (eglot--glob-match "foo/**/*.js" "foo/bar/baz/foo.js"))
+  (should-not (eglot--glob-match "foo/**/*.js" "foo/bar/baz/foo.jsx"))
+  (should (eglot--glob-match "*.{js,ts}" "foo.js"))
+  (should-not (eglot--glob-match "*.{js,ts}" "foo.xs"))
+  (should (eglot--glob-match "foo/**/*.{js,ts}" "foo/bar/baz/foo.ts"))
+  (should (eglot--glob-match "foo/**/*.{js,ts}x" "foo/bar/baz/foo.tsx"))
+  (should (eglot--glob-match "?oo.js" "foo.js"))
+  (should (eglot--glob-match "foo/**/*.{js,ts}?" "foo/bar/baz/foo.tsz"))
+  (should (eglot--glob-match "foo/**/*.{js,ts}?" "foo/bar/baz/foo.tsz"))
+  (should (eglot--glob-match "example.[!0-9]" "example.a"))
+  (should-not (eglot--glob-match "example.[!0-9]" "example.0"))
+  (should (eglot--glob-match "example.[0-9]" "example.0"))
+  (should-not (eglot--glob-match "example.[0-9]" "example.a"))
+  (should (eglot--glob-match "**/bar/" "foo/bar/"))
+  (should-not (eglot--glob-match "foo.hs" "fooxhs"))
+
+  ;; Some more tests
+  (should (eglot--glob-match "**/.*" ".git"))
+  (should (eglot--glob-match ".?" ".o"))
+  (should (eglot--glob-match "**/.*" ".hidden.txt"))
+  (should (eglot--glob-match "**/.*" "path/.git"))
+  (should (eglot--glob-match "**/.*" "path/.hidden.txt"))
+  (should (eglot--glob-match "**/node_modules/**" "node_modules/"))
+  (should (eglot--glob-match "{foo,bar}/**" "foo/test"))
+  (should (eglot--glob-match "{foo,bar}/**" "bar/test"))
+  (should (eglot--glob-match "some/**/*" "some/foo.js"))
+  (should (eglot--glob-match "some/**/*" "some/folder/foo.js"))
+
+  ;; VSCode supposedly supports this, not sure if good idea.
+  ;;
+  ;; (should (eglot--glob-match "**/node_modules/**" "node_modules"))
+  ;; (should (eglot--glob-match "{foo,bar}/**" "foo"))
+  ;; (should (eglot--glob-match "{foo,bar}/**" "bar"))
+
+  ;; VSCode also supports nested blobs.  Do we care?
+  ;;
+  ;; (should (eglot--glob-match "{**/*.d.ts,**/*.js}" "/testing/foo.js"))
+  ;; (should (eglot--glob-match "{**/*.d.ts,**/*.js}" "testing/foo.d.ts"))
+  ;; (should (eglot--glob-match "{**/*.d.ts,**/*.js,foo.[0-9]}" "foo.5"))
+  ;; (should (eglot--glob-match "prefix/{**/*.d.ts,**/*.js,foo.[0-9]}" 
"prefix/foo.8"))
+  )
+
+(defvar tramp-histfile-override)
+(defun eglot--call-with-tramp-test (fn)
+  ;; Set up a Tramp method that’s just a shell so the remote host is
+  ;; really just the local host.
+  (let* ((tramp-remote-path (cons 'tramp-own-remote-path tramp-remote-path))
+         (tramp-histfile-override t)
+         (tramp-verbose 1)
+         (temporary-file-directory ert-remote-temporary-file-directory)
+         (default-directory temporary-file-directory))
+    ;; We must check the remote LSP server.  So far, just "clangd" is used.
+    (unless (executable-find "clangd" 'remote)
+      (ert-skip "Remote clangd not found"))
+    (funcall fn)))
+
+(ert-deftest eglot-test-tramp-test ()
+  "Ensure LSP servers can be used over TRAMP."
+  :tags '(:expensive-test)
+  (eglot--call-with-tramp-test #'eglot-tests--auto-detect-running-server-1))
+
+(ert-deftest eglot-test-tramp-test-2 ()
+  "Ensure LSP servers can be used over TRAMP."
+  :tags '(:expensive-test)
+  (eglot--call-with-tramp-test #'eglot-tests--lsp-abiding-column-1))
+
+(ert-deftest eglot-test-path-to-uri-windows ()
+  (skip-unless (eq system-type 'windows-nt))
+  (should (string-prefix-p "file:///"
+                             (eglot--path-to-uri "c:/Users/Foo/bar.lisp")))
+  (should (string-suffix-p "c%3A/Users/Foo/bar.lisp"
+                           (eglot--path-to-uri "c:/Users/Foo/bar.lisp"))))
+
+(ert-deftest eglot-test-same-server-multi-mode ()
+  "Check single LSP instance manages multiple modes in same project."
+  (skip-unless (executable-find "clangd"))
+  (let (server)
+    (eglot--with-fixture
+        `(("project" . (("foo.cpp" .
+                         "#include \"foolib.h\"
+                        int main() { return foo(); }")
+                        ("foolib.h" .
+                         "#ifdef __cplusplus\nextern \"C\" {\n#endif
+                        int foo();
+                        #ifdef __cplusplus\n}\n#endif")
+                        ("foolib.c" .
+                         "#include \"foolib.h\"
+                        int foo() {return 42;}"))))
+      (with-current-buffer
+          (eglot--find-file-noselect "project/foo.cpp")
+        (should (setq server (eglot--tests-connect))))
+      (with-current-buffer
+          (eglot--find-file-noselect "project/foolib.h")
+        (should (eq (eglot-current-server) server)))
+      (with-current-buffer
+          (eglot--find-file-noselect "project/foolib.c")
+        (should (eq (eglot-current-server) server))))))
+
+(provide 'eglot-tests)
+;;; eglot-tests.el ends here
+
+;; Local Variables:
+;; checkdoc-force-docstrings-flag: nil
+;; End:
diff --git a/test/lisp/progmodes/project-resources/.dir-locals.el 
b/test/lisp/progmodes/project-resources/.dir-locals.el
new file mode 100644
index 0000000000..a311b7efa9
--- /dev/null
+++ b/test/lisp/progmodes/project-resources/.dir-locals.el
@@ -0,0 +1 @@
+((nil . ((project-vc-ignores . ("etc")))))
diff --git a/test/lisp/progmodes/project-resources/etc 
b/test/lisp/progmodes/project-resources/etc
new file mode 100644
index 0000000000..dd7999bd3d
--- /dev/null
+++ b/test/lisp/progmodes/project-resources/etc
@@ -0,0 +1 @@
+etc
\ No newline at end of file
diff --git a/test/lisp/progmodes/project-resources/foo 
b/test/lisp/progmodes/project-resources/foo
new file mode 100644
index 0000000000..1910281566
--- /dev/null
+++ b/test/lisp/progmodes/project-resources/foo
@@ -0,0 +1 @@
+foo
\ No newline at end of file
diff --git a/test/lisp/progmodes/project-tests.el 
b/test/lisp/progmodes/project-tests.el
index c3b886873d..8814f30b04 100644
--- a/test/lisp/progmodes/project-tests.el
+++ b/test/lisp/progmodes/project-tests.el
@@ -41,7 +41,7 @@ quoted directory names (Bug#47799)."
   (skip-unless (executable-find "grep"))
   (ert-with-temp-directory directory
     (let ((default-directory directory)
-          (project-current-inhibit-prompt t)
+          (project-current-directory-override t)
           (project-find-functions nil)
           (project-list-file
            (expand-file-name "projects" directory))
@@ -139,4 +139,17 @@ When `project-ignores' includes a name matching project 
dir."
     (should-not (null project))
     (should (string-match-p "/test/lisp/\\'" (project-root project)))))
 
+(ert-deftest project-vc-supports-project-in-different-dir ()
+  "Check that it picks up dir-locals settings from somewhere else."
+  (skip-unless (eq (vc-responsible-backend default-directory) 'Git))
+  (let* ((dir (ert-resource-directory))
+         (_ (vc-file-clearprops dir))
+         (project-vc-extra-root-markers '(".dir-locals.el"))
+         (project (project-current nil dir)))
+    (should-not (null project))
+    (should (string-match-p "/test/lisp/progmodes/project-resources/\\'" 
(project-root project)))
+    (should (member "etc" (project-ignores project dir)))
+    (should (equal '(".dir-locals.el" "foo")
+                   (mapcar #'file-name-nondirectory (project-files 
project))))))
+
 ;;; project-tests.el ends here
diff --git a/test/lisp/progmodes/ruby-mode-resources/ruby.rb 
b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
index f39489071e..2451edaee2 100644
--- a/test/lisp/progmodes/ruby-mode-resources/ruby.rb
+++ b/test/lisp/progmodes/ruby-mode-resources/ruby.rb
@@ -174,6 +174,12 @@ qux :+,
     bar,
     :a
 
+zzz @abc,
+    4
+
+foo a = 5,
+    b
+
 b = $:
 c = ??
 
@@ -500,3 +506,35 @@ def resolve(**args)
 
   member.call(**args)
 end
+
+# Endless methods.
+class Bar
+  def foo(abc) = bar +
+                 baz
+
+  def self.bar =
+    123 +
+    4
+
+  def foo(...) = z
+
+  def request_params = {
+    headers: request_headers,
+    body: request_body
+  }
+
+  def self.foo(
+        baz,
+        bar
+      ) =
+    what
+
+  def foo=(
+        baz,
+        bar
+      )
+    def baz.full_name = "#{bar} 3"
+
+    baz
+  end
+end
diff --git a/test/lisp/progmodes/ruby-mode-tests.el 
b/test/lisp/progmodes/ruby-mode-tests.el
index 33fded5a59..9be01dc78f 100644
--- a/test/lisp/progmodes/ruby-mode-tests.el
+++ b/test/lisp/progmodes/ruby-mode-tests.el
@@ -578,6 +578,45 @@ VALUES-PLIST is a list with alternating index and value 
elements."
     (search-backward "_")
     (should (string= (ruby-add-log-current-method) "M::C#foo"))))
 
+(ert-deftest ruby-add-log-current-method-after-inner-class-outside-methods ()
+  (ruby-with-temp-buffer (ruby-test-string
+                          "module M
+                          |  class C
+                          |    class D
+                          |    end
+                          |
+                          |_
+                          |  end
+                          |end")
+    (search-backward "_")
+    (delete-char 1)
+    (should (string= (ruby-add-log-current-method) "M::C"))))
+
+(ert-deftest 
ruby-add-log-current-method-after-inner-class-outside-methods-with-text ()
+  (ruby-with-temp-buffer (ruby-test-string
+                          "module M
+                          |  class C
+                          |    class D
+                          |    end
+                          |
+                          |    FOO = 5
+                          |  end
+                          |end")
+    (search-backward "FOO")
+    (should (string= (ruby-add-log-current-method) "M::C"))))
+
+(ert-deftest ruby-add-log-current-method-after-endless-method ()
+  (ruby-with-temp-buffer (ruby-test-string
+                          "module M
+                          |  class C
+                          |    def foo =
+                          |      4_
+                          |  end
+                          |end")
+    (search-backward "_")
+    (delete-char 1)
+    (should (string= (ruby-add-log-current-method) "M::C#foo"))))
+
 (defvar ruby-block-test-example
   (ruby-test-string
    "class C
diff --git a/test/lisp/server-tests.el b/test/lisp/server-tests.el
index ebf84481c6..5ef66052c8 100644
--- a/test/lisp/server-tests.el
+++ b/test/lisp/server-tests.el
@@ -218,8 +218,8 @@ long as this works, the problem in bug#58877 shouldn't 
occur."
                  (eq (terminal-live-p terminal) t)
                  (not (eq system-type 'windows-nt)))
         (delete-terminal terminal)))
-    ;; Delete the created frame.
-    (delete-frame (car (cl-set-difference (frame-list) starting-frames))
-                  t)))
+    ;; If there are any new frames remaining, delete them.
+    (mapc (lambda (frame) (delete-frame frame t))
+          (cl-set-difference (frame-list) starting-frames))))
 
 ;;; server-tests.el ends here
diff --git a/test/lisp/use-package/use-package-tests.el 
b/test/lisp/use-package/use-package-tests.el
new file mode 100644
index 0000000000..e4586b04f2
--- /dev/null
+++ b/test/lisp/use-package/use-package-tests.el
@@ -0,0 +1,1959 @@
+;;; use-package-tests.el --- Tests for use-package.el  -*- lexical-binding: t; 
-*-
+
+;; Copyright (C) 2014-2022 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 'cl-lib)
+(require 'ert)
+(require 'use-package)
+
+(setq use-package-always-ensure nil
+      use-package-verbose 'errors
+      use-package-expand-minimally t
+      ;; These are needed for certain tests below where the `pcase' match
+      ;; expression is large and contains holes, such as the :after tests.
+      max-lisp-eval-depth 8000
+      max-specpdl-size 8000)
+
+(unless (fboundp 'macroexpand-1)
+  (defun macroexpand-1 (form &optional environment)
+    "Perform (at most) one step of macroexpansion."
+    (cond
+     ((consp form)
+      (let* ((head (car form))
+             (env-expander (assq head environment)))
+        (if env-expander
+            (if (cdr env-expander)
+                (apply (cdr env-expander) (cdr form))
+              form)
+          (if (not (and (symbolp head) (fboundp head)))
+              form
+            (let ((def (autoload-do-load (symbol-function head) head 'macro)))
+              (cond
+               ;; Follow alias, but only for macros, otherwise we may end up
+               ;; skipping an important compiler-macro (e.g. 
cl--block-wrapper).
+               ((and (symbolp def) (macrop def)) (cons def (cdr form)))
+               ((not (consp def)) form)
+               (t
+                (if (eq 'macro (car def))
+                    (apply (cdr def) (cdr form))
+                  form))))))))
+     (t form))))
+
+(defmacro expand-minimally (form)
+  `(let ((use-package-verbose 'errors)
+         (use-package-expand-minimally t))
+     (macroexpand-1 ',form)))
+
+(defmacro expand-maximally (form)
+  `(let ((use-package-verbose 'debug)
+         (use-package-expand-minimally nil))
+     (macroexpand-1 ',form)))
+
+(defmacro match-expansion (form &rest value)
+  `(should (pcase (expand-minimally ,form)
+             ,@(mapcar #'(lambda (x) (list x t)) value))))
+
+(defun fix-expansion ()
+  (interactive)
+  (save-excursion
+    (unless (looking-at "(match-expansion")
+      (backward-up-list))
+    (when (looking-at "(match-expansion")
+      (re-search-forward "(\\(use-package\\|bind-key\\)")
+      (goto-char (match-beginning 0))
+      (let ((decl (read (current-buffer))))
+        (kill-sexp)
+        (let (vars)
+          (catch 'exit
+            (save-excursion
+              (while (ignore-errors (backward-up-list) t)
+                (when (looking-at "(let\\s-+")
+                  (goto-char (match-end 0))
+                  (setq vars (read (current-buffer)))
+                  (throw 'exit t)))))
+          (eval
+           `(let (,@ (append vars
+                             '((use-package-verbose 'errors)
+                               (use-package-expand-minimally t))))
+              (insert ?\n ?\` (pp-to-string (macroexpand-1 decl))))))))))
+
+(bind-key "C-c C-u" #'fix-expansion emacs-lisp-mode-map)
+
+(ert-deftest use-package-test-recognize-function ()
+  (should (use-package-recognize-function nil t))
+  (should-not (use-package-recognize-function nil))
+  (should (use-package-recognize-function t))
+  (should (use-package-recognize-function 'sym))
+  (should (use-package-recognize-function #'sym))
+  (should (use-package-recognize-function (lambda () ...)))
+  (should (use-package-recognize-function '(lambda () ...)))
+  (should (use-package-recognize-function #'(lambda () ...)))
+
+  (should-not (use-package-recognize-function 1))
+  (should-not (use-package-recognize-function "Hello"))
+  (should-not (use-package-recognize-function '(nil . nil))))
+
+(ert-deftest use-package-test-normalize-function ()
+  (should (equal (use-package-normalize-function nil) nil))
+  (should (equal (use-package-normalize-function t) t))
+  (should (equal (use-package-normalize-function 'sym) 'sym))
+  (should (equal (use-package-normalize-function #'sym) 'sym))
+  (should (equal (use-package-normalize-function '(lambda () ...)) '(lambda () 
...)))
+  (should (equal (use-package-normalize-function ''(lambda () ...)) '(lambda 
() ...)))
+  (should (equal (use-package-normalize-function '#'(lambda () ...)) '(lambda 
() ...)))
+
+  (should (equal (use-package-normalize-function 1) 1))
+  (should (equal (use-package-normalize-function "Hello") "Hello"))
+  (should (equal (use-package-normalize-function '(nil . nil)) '(nil . nil))))
+
+(ert-deftest use-package-test/:disabled-1 ()
+  (match-expansion
+   (use-package foo :disabled t)
+   `()))
+
+(ert-deftest use-package-test/:preface-1 ()
+  (match-expansion
+   (use-package foo :preface (t))
+   `(progn
+      (eval-and-compile
+        (t))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:preface-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :preface (t))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t))))
+          (t))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:preface-3 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo
+       :preface (preface)
+       :init (init)
+       :config (config)
+       :functions func
+       :defines def)
+     `(progn
+        (eval-and-compile
+          (defvar def)
+          (declare-function func "foo")
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t))))
+          (preface))
+        (init)
+        (require 'foo nil nil)
+        (config)
+        t))))
+
+(ert-deftest use-package-test/:preface-4 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo
+       :preface (preface)
+       :init (init)
+       :config (config)
+       :functions func
+       :defines def
+       :defer t)
+     `(progn
+        (eval-and-compile
+          (defvar def)
+          (declare-function func "foo")
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t))))
+          (preface))
+        (init)
+        (eval-after-load 'foo
+          '(progn
+             (config)
+             t))))))
+
+(ert-deftest use-package-test/:pin-1 ()
+  (match-expansion
+   (use-package foo :pin foo)
+   `(progn
+      (use-package-pin-package 'foo "foo")
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:pin-2 ()
+  (match-expansion
+   (use-package foo :pin "foo")
+   `(progn
+      (use-package-pin-package 'foo "foo")
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test-normalize/:ensure ()
+  (cl-flet ((norm (&rest args)
+                  (apply #'use-package-normalize/:ensure
+                         'foopkg :ensure args)))
+    (should (equal (norm '(t)) '(t)))
+    (should (equal (norm '(nil)) '(nil)))
+    (should (equal (norm '(sym)) '(sym)))
+    (should-error (norm '(1)))
+    (should-error (norm '("Hello")))))
+
+(ert-deftest use-package-test/:ensure-1 ()
+  (let ((use-package-always-ensure nil))
+    (match-expansion
+     (use-package foo :ensure t)
+     `(progn
+        (use-package-ensure-elpa 'foo '(t) 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-2 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :ensure t)
+     `(progn
+        (use-package-ensure-elpa 'foo '(t) 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-3 ()
+  (let ((use-package-always-ensure nil))
+    (match-expansion
+     (use-package foo :ensure nil)
+     `(progn
+        (use-package-ensure-elpa 'foo '(nil) 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-4 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :ensure nil)
+     `(progn
+        (use-package-ensure-elpa 'foo '(nil) 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-5 ()
+  (let ((use-package-always-ensure nil))
+    (match-expansion
+     (use-package foo :load-path "foo")
+     `(progn
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-6 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :load-path "foo")
+     `(progn
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-7 ()
+  (let ((use-package-always-ensure nil))
+    (match-expansion
+     (use-package foo :ensure nil :load-path "foo")
+     `(progn
+        (use-package-ensure-elpa 'foo '(nil) 'nil)
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-8 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :ensure nil :load-path "foo")
+     `(progn
+        (use-package-ensure-elpa 'foo '(nil) 'nil)
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-9 ()
+  (let ((use-package-always-ensure nil))
+    (match-expansion
+     (use-package foo :ensure t :load-path "foo")
+     `(progn
+        (use-package-ensure-elpa 'foo '(t) 'nil)
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-10 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :ensure t :load-path "foo")
+     `(progn
+        (use-package-ensure-elpa 'foo '(t) 'nil)
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-11 ()
+  (let (tried-to-install)
+    (cl-letf (((symbol-function #'use-package-ensure-elpa)
+               (lambda (name ensure state &optional no-refresh)
+                 (when ensure
+                   (setq tried-to-install name))))
+              ((symbol-function #'require) #'ignore))
+      (use-package foo :ensure t)
+      (should (eq tried-to-install 'foo)))))
+
+(ert-deftest use-package-test/:ensure-12 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :ensure bar)
+     `(progn
+        (use-package-ensure-elpa 'foo '(bar) 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-13 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo :ensure bar :ensure quux)
+     `(progn
+        (use-package-ensure-elpa 'foo '(bar quux) 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:ensure-14 ()
+  (match-expansion
+   (use-package ess-site
+     :ensure ess1
+     :ensure ess2
+     :ensure (ess3 :pin "melpa-unstable")
+     :pin melpa-stable)
+   `(progn
+      (use-package-pin-package 'ess-site "melpa-stable")
+      (use-package-ensure-elpa 'ess-site
+                               '(ess1 ess2
+                                      (ess3 . "melpa-unstable"))
+                               'nil)
+      (require 'ess-site nil nil))))
+
+(ert-deftest use-package-test/:ensure-15 ()
+  (let ((use-package-always-ensure t))
+    (match-expansion
+     (use-package foo
+       :pin "elpa"
+       :ensure bar
+       :ensure (quux :pin "melpa"))
+     `(progn
+        (use-package-pin-package 'foo "elpa")
+        (use-package-ensure-elpa 'foo
+                                 '(bar
+                                   (quux . "melpa"))
+                                 'nil)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:if-1 ()
+  (match-expansion
+   (use-package foo :if t)
+   `(when t
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:if-2 ()
+  (match-expansion
+   (use-package foo :if (and t t))
+   `(when (and t t)
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:if-3 ()
+  (match-expansion
+   (use-package foo :if nil)
+   `(when nil
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:when-1 ()
+  (match-expansion
+   (use-package foo :when t)
+   `(when t
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:when-2 ()
+  (match-expansion
+   (use-package foo :when (and t t))
+   `(when (and t t)
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:when-3 ()
+  (match-expansion
+   (use-package foo :when nil)
+   `(when nil
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:unless-1 ()
+  (match-expansion
+   (use-package foo :unless t)
+   `(when (not t)
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:unless-2 ()
+  (match-expansion
+   (use-package foo :unless (and t t))
+   `(when (not (and t t))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:unless-3 ()
+  (match-expansion
+   (use-package foo :unless nil)
+   `(unless nil
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:requires-1 ()
+  (match-expansion
+   (use-package foo :requires bar)
+   `(when (featurep 'bar)
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:requires-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :requires bar)
+     `(when (featurep 'bar)
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:requires-3 ()
+  (match-expansion
+   (use-package foo :requires (bar quux))
+   `(when (not (member nil (mapcar #'featurep '(bar quux))))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:requires-4 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :requires bar)
+     `(when (featurep 'bar)
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:load-path-1 ()
+  (match-expansion
+   (use-package foo :load-path "bar")
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path
+                     ,(pred (apply-partially
+                             #'string=
+                             (expand-file-name
+                              "bar" user-emacs-directory)))))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:load-path-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :load-path "bar")
+     `(progn
+        (eval-and-compile
+          (add-to-list 'load-path
+                       ,(pred (apply-partially
+                               #'string=
+                               (expand-file-name
+                                "bar" user-emacs-directory)))))
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:load-path-3 ()
+  (match-expansion
+   (use-package foo :load-path ("bar" "quux"))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path
+                     ,(pred (apply-partially
+                             #'string=
+                             (expand-file-name
+                              "bar" user-emacs-directory)))))
+      (eval-and-compile
+        (add-to-list 'load-path
+                     ,(pred (apply-partially
+                             #'string=
+                             (expand-file-name
+                              "quux" user-emacs-directory)))))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:load-path-4 ()
+  (match-expansion
+   (use-package foo :load-path (lambda () (list "bar" "quux")))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path
+                     ,(pred (apply-partially
+                             #'string=
+                             (expand-file-name
+                              "bar" user-emacs-directory)))))
+      (eval-and-compile
+        (add-to-list 'load-path
+                     ,(pred (apply-partially
+                             #'string=
+                             (expand-file-name
+                              "quux" user-emacs-directory)))))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:no-require-1 ()
+  (match-expansion
+   (use-package foo :no-require t)
+   `nil))
+
+(ert-deftest use-package-test/:no-require-2 ()
+  (match-expansion
+   (use-package foo :no-require t :config (config))
+   `(progn
+      (config)
+      t)))
+
+(ert-deftest use-package-test/:no-require-3 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :no-require t)
+     `(eval-and-compile
+        (eval-when-compile
+          (with-demoted-errors "Cannot load foo: %S" nil nil))))))
+
+(defun use-package-test-normalize-bind (&rest args)
+  (apply #'use-package-normalize-binder 'foo :bind args))
+
+(ert-deftest use-package-test-normalize/:bind-1 ()
+  (should (equal (use-package-test-normalize-bind
+                  '(("C-a" . alpha)))
+                 '(("C-a" . alpha)))))
+
+(ert-deftest use-package-test-normalize/:bind-2 ()
+  (should (equal (use-package-test-normalize-bind
+                  '(("C-a" . alpha)
+                    :map foo-map
+                    ("C-b" . beta)))
+                 '(("C-a" . alpha)
+                   :map foo-map
+                   ("C-b" . beta)))))
+
+(ert-deftest use-package-test-normalize/:bind-3 ()
+  (should (equal (use-package-test-normalize-bind
+                  '(:map foo-map
+                         ("C-a" . alpha)
+                         ("C-b" . beta)))
+                 '(:map foo-map
+                        ("C-a" . alpha)
+                        ("C-b" . beta)))))
+
+(ert-deftest use-package-test/:bind-1 ()
+  (match-expansion
+   (use-package foo :bind ("C-k" . key1) ("C-u" . key2))
+   `(progn
+      (unless
+          (fboundp 'key1)
+        (autoload #'key1 "foo" nil t))
+      (unless
+          (fboundp 'key2)
+        (autoload #'key2 "foo" nil t))
+      (bind-keys :package foo
+                 ("C-k" . key1)
+                 ("C-u" . key2)))))
+
+(ert-deftest use-package-test/:bind-2 ()
+  (match-expansion
+   (use-package foo :bind (("C-k" . key1) ("C-u" . key2)))
+   `(progn
+      (unless (fboundp 'key1)
+        (autoload #'key1 "foo" nil t))
+      (unless (fboundp 'key2)
+        (autoload #'key2 "foo" nil t))
+      (bind-keys :package foo
+                 ("C-k" . key1)
+                 ("C-u" . key2)))))
+
+(ert-deftest use-package-test/:bind-3 ()
+  (match-expansion
+   (use-package foo :bind (:map my-map ("C-k" . key1) ("C-u" . key2)))
+   `(progn
+      (unless
+          (fboundp 'key1)
+        (autoload #'key1 "foo" nil t))
+      (unless
+          (fboundp 'key2)
+        (autoload #'key2 "foo" nil t))
+      (bind-keys :package foo :map my-map
+                 ("C-k" . key1)
+                 ("C-u" . key2)))))
+
+(ert-deftest use-package-test/:bind-4 ()
+  (should-error
+   (match-expansion
+    (use-package foo :bind :map my-map ("C-k" . key1) ("C-u" . key2))
+    `(bind-keys :package foo))))
+
+(ert-deftest use-package-test/:bind-5 ()
+  (match-expansion
+   (use-package foo :bind ("C-k" . key1) (:map my-map ("C-u" . key2)))
+   `(progn
+      (unless (fboundp 'key1)
+        (autoload #'key1 "foo" nil t))
+      (unless (fboundp 'key2)
+        (autoload #'key2 "foo" nil t))
+      (bind-keys :package foo
+                 ("C-k" . key1)
+                 :map my-map
+                 ("C-u" . key2)))))
+
+(ert-deftest use-package-test/:bind-6 ()
+  (match-expansion
+   (use-package foo
+     :bind
+     ("C-k" . key1)
+     (:map my-map ("C-u" . key2))
+     (:map my-map2 ("C-u" . key3)))
+   `(progn
+      (unless (fboundp 'key1)
+        (autoload #'key1 "foo" nil t))
+      (unless (fboundp 'key2)
+        (autoload #'key2 "foo" nil t))
+      (unless (fboundp 'key3)
+        (autoload #'key3 "foo" nil t))
+      (bind-keys :package foo
+                 ("C-k" . key1)
+                 :map my-map ("C-u" . key2)
+                 :map my-map2 ("C-u" . key3)))))
+
+(ert-deftest use-package-test/:bind-7 ()
+  (match-expansion
+   (use-package foo
+     :ensure
+     :bind ("C-c r" . browse-at-remote))
+   `(progn
+      (use-package-ensure-elpa 'foo '(t) 'nil)
+      (unless (fboundp 'browse-at-remote)
+        (autoload #'browse-at-remote "foo" nil t))
+      (bind-keys :package foo ("C-c r" . browse-at-remote)))))
+
+(ert-deftest use-package-test/:bind-8 ()
+  (match-expansion
+   (use-package foo
+     :ensure
+     :bind (:map foo-map
+                 (("C-c r" . foo)
+                  ("C-c r" . bar))))
+   `(progn
+      (use-package-ensure-elpa 'foo '(t) 'nil)
+      (unless (fboundp 'foo)
+        (autoload #'foo "foo" nil t))
+      (unless (fboundp 'bar)
+        (autoload #'bar "foo" nil t))
+      (bind-keys :package foo :map foo-map
+                 ("C-c r" . foo)
+                 ("C-c r" . bar)))))
+
+(ert-deftest use-package-test/:bind*-1 ()
+  (match-expansion
+   (use-package foo :bind* ("C-k" . key))
+   `(progn
+      (unless (fboundp 'key)
+        (autoload #'key "foo" nil t))
+      (bind-keys* :package foo ("C-k" . key)))))
+
+(ert-deftest use-package-test/:bind-keymap-1 ()
+  (match-expansion
+   (use-package foo :bind-keymap ("C-k" . key))
+   `(bind-key "C-k"
+              #'(lambda nil
+                  (interactive)
+                  (use-package-autoload-keymap 'key 'foo nil)))))
+
+(ert-deftest use-package-test/:bind-keymap*-1 ()
+  (match-expansion
+   (use-package foo :bind-keymap* ("C-k" . key))
+   `(bind-key* "C-k"
+               #'(lambda ()
+                   (interactive)
+                   (use-package-autoload-keymap 'key 'foo t)))))
+
+(ert-deftest use-package-test/:interpreter-1 ()
+  (match-expansion
+   (use-package foo :interpreter "interp")
+   `(progn
+      (unless (fboundp 'foo)
+        (autoload #'foo "foo" nil t))
+      (add-to-list 'interpreter-mode-alist '("interp" . foo)))))
+
+(ert-deftest use-package-test/:interpreter-2 ()
+  (match-expansion
+   (use-package foo :interpreter ("interp" . fun))
+   `(progn
+      (unless (fboundp 'fun)
+        (autoload #'fun "foo" nil t))
+      (add-to-list 'interpreter-mode-alist '("interp" . fun)))))
+
+(ert-deftest use-package-test-normalize/:mode ()
+  (cl-flet ((norm (&rest args)
+                  (apply #'use-package-normalize/:mode
+                         'foopkg :mode args)))
+    (should (equal (norm '(".foo"))
+                   '((".foo" . foopkg))))
+    (should (equal (norm '(".foo" ".bar"))
+                   '((".foo" . foopkg) (".bar" . foopkg))))
+    (should (equal (norm '((".foo" ".bar")))
+                   '((".foo" . foopkg) (".bar" . foopkg))))
+    (should (equal (norm '((".foo")))
+                   '((".foo" . foopkg))))
+    (should (equal (norm '((".foo" . foo) (".bar" . bar)))
+                   '((".foo" . foo) (".bar" . bar))))))
+
+(ert-deftest use-package-test/:mode-1 ()
+  (match-expansion
+   (use-package foo :mode "interp")
+   `(progn
+      (unless (fboundp 'foo)
+        (autoload #'foo "foo" nil t))
+      (add-to-list 'auto-mode-alist '("interp" . foo)))))
+
+(ert-deftest use-package-test/:mode-2 ()
+  (match-expansion
+   (use-package foo :mode ("interp" . fun))
+   `(progn
+      (unless (fboundp 'fun)
+        (autoload #'fun "foo" nil t))
+      (add-to-list 'auto-mode-alist '("interp" . fun)))))
+
+(ert-deftest use-package-test/:magic-1 ()
+  (match-expansion
+   (use-package foo :magic "interp")
+   `(progn
+      (unless (fboundp 'foo)
+        (autoload #'foo "foo" nil t))
+      (add-to-list 'magic-mode-alist '("interp" . foo)))))
+
+(ert-deftest use-package-test/:magic-2 ()
+  (match-expansion
+   (use-package foo :magic ("interp" . fun))
+   `(progn
+      (unless (fboundp 'fun)
+        (autoload #'fun "foo" nil t))
+      (add-to-list 'magic-mode-alist '("interp" . fun)))))
+
+(ert-deftest use-package-test/:magic-fallback-1 ()
+  (match-expansion
+   (use-package foo :magic-fallback "interp")
+   `(progn
+      (unless (fboundp 'foo)
+        (autoload #'foo "foo" nil t))
+      (add-to-list 'magic-fallback-mode-alist '("interp" . foo)))))
+
+(ert-deftest use-package-test/:magic-fallback-2 ()
+  (match-expansion
+   (use-package foo :magic-fallback ("interp" . fun))
+   `(progn
+      (unless (fboundp 'fun)
+        (autoload #'fun "foo" nil t))
+      (add-to-list 'magic-fallback-mode-alist '("interp" . fun)))))
+
+(ert-deftest use-package-test/:commands-1 ()
+  (match-expansion
+   (use-package foo :commands bar)
+   `(unless (fboundp 'bar)
+      (autoload #'bar "foo" nil t))))
+
+(ert-deftest use-package-test/:commands-2 ()
+  (match-expansion
+   (use-package foo :commands (bar quux))
+   `(progn
+      (unless (fboundp 'bar)
+        (autoload #'bar "foo" nil t))
+      (unless (fboundp 'quux)
+        (autoload #'quux "foo" nil t)))))
+
+(ert-deftest use-package-test/:commands-3 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :commands (bar quux))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (unless (fboundp 'bar)
+          (autoload #'bar "foo" nil t))
+        (eval-when-compile
+          (declare-function bar "foo"))
+        (unless (fboundp 'quux)
+          (autoload #'quux "foo" nil t))
+        (eval-when-compile
+          (declare-function quux "foo"))))))
+
+(ert-deftest use-package-test/:commands-4 ()
+  (match-expansion
+   (use-package foo :commands bar :init (bar))
+   `(progn
+      (unless
+          (fboundp 'bar)
+        (autoload #'bar "foo" nil t))
+      (bar))))
+
+(ert-deftest use-package-test/:commands-5 ()
+  (match-expansion
+   (use-package gnus-harvest
+     :load-path "foo"
+     :commands gnus-harvest-install
+     :demand t
+     :config
+     (if (featurep 'message-x)
+         (gnus-harvest-install 'message-x)
+       (gnus-harvest-install)))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path ,(pred stringp)))
+      (require 'gnus-harvest nil nil)
+      (if (featurep 'message-x)
+          (gnus-harvest-install 'message-x)
+        (gnus-harvest-install))
+      t)))
+
+(ert-deftest use-package-test/:commands-6 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package gnus-harvest
+       :load-path "foo"
+       :commands gnus-harvest-install
+       :demand t
+       :config
+       (if (featurep 'message-x)
+           (gnus-harvest-install 'message-x)
+         (gnus-harvest-install)))
+     `(progn
+        (eval-and-compile
+          (add-to-list 'load-path ,(pred stringp)))
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load gnus-harvest: %S" nil
+                                 (unless (featurep 'gnus-harvest)
+                                   (load "gnus-harvest" nil t)))))
+        (eval-when-compile
+          (declare-function gnus-harvest-install "gnus-harvest"))
+        (require 'gnus-harvest nil nil)
+        (if
+            (featurep 'message-x)
+            (gnus-harvest-install 'message-x)
+          (gnus-harvest-install))
+        t))))
+
+(ert-deftest use-package-test/:autoload-1 ()
+  (match-expansion
+   (use-package foo :autoload bar)
+   `(unless (fboundp 'bar)
+      (autoload #'bar "foo"))))
+
+(ert-deftest use-package-test/:defines-1 ()
+  (match-expansion
+   (use-package foo :defines bar)
+   `(require 'foo nil nil)))
+
+(ert-deftest use-package-test/:defines-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :defines bar)
+     `(progn
+        (eval-and-compile
+          (defvar bar)
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:functions-1 ()
+  (match-expansion
+   (use-package foo :functions bar)
+   `(require 'foo nil nil)))
+
+(ert-deftest use-package-test/:functions-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :functions bar)
+     `(progn
+        (eval-and-compile
+          (declare-function bar "foo")
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:functions-3 ()
+  (match-expansion
+   (use-package foo :defer t :functions bar)
+   `nil))
+
+(ert-deftest use-package-test/:functions-4 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :defer t :functions bar)
+     `(eval-and-compile
+        (declare-function bar "foo")
+        (eval-when-compile
+          (with-demoted-errors "Cannot load foo: %S" nil
+                               (unless (featurep 'foo)
+                                 (load "foo" nil t))))))))
+
+(ert-deftest use-package-test/:functions-5 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :defer t :config (config) :functions bar)
+     `(progn
+        (eval-and-compile
+          (declare-function bar "foo")
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t)))))
+        (eval-after-load 'foo
+          '(progn
+             (config)
+             t))))))
+
+(ert-deftest use-package-test/:defer-1 ()
+  (match-expansion
+   (use-package foo)
+   `(require 'foo nil nil)))
+
+(ert-deftest use-package-test/:defer-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo)
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:defer-3 ()
+  (match-expansion
+   (use-package foo :defer t)
+   `nil))
+
+(ert-deftest use-package-test/:defer-4 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :defer t)
+     `(eval-and-compile
+        (eval-when-compile
+          (with-demoted-errors "Cannot load foo: %S" nil
+                               (unless (featurep 'foo)
+                                 (load "foo" nil t))))))))
+
+(ert-deftest use-package-test-normalize/:hook ()
+  (cl-flet ((norm (&rest args)
+                  (apply #'use-package-normalize/:hook
+                         'foopkg :hook args)))
+    (should-error (norm nil))
+    (should (equal (norm '(bar))
+                   '((bar . foopkg-mode))))
+    (should (equal (norm '((bar . foopkg)))
+                   '((bar . foopkg))))
+    (should (equal (norm '((bar . baz)))
+                   '((bar . baz))))
+    (should (equal (norm '(((bar baz) . quux)))
+                   '(((bar baz) . quux))))
+    (should (equal (norm '(bar baz))
+                   '(((bar baz) . foopkg-mode))))
+    (should (equal (norm '((bar baz) (quux bow)))
+                   '(((bar baz) . foopkg-mode) ((quux bow) . foopkg-mode))))
+    (should (equal (norm '((bar . baz) (quux . bow)))
+                   '((bar . baz) (quux . bow))))
+    (should (equal (norm '(((bar1 bar2) . baz) ((quux1 quux2) . bow)))
+                   '(((bar1 bar2) . baz) ((quux1 quux2) . bow))))))
+
+(ert-deftest use-package-test/:hook-1 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo
+       :bind (("C-a" . key))
+       :hook (hook . fun))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors
+                "Cannot load foo: %S" nil
+                (unless (featurep 'foo)
+                  (load "foo" nil t)))))
+        (unless
+            (fboundp 'key)
+          (autoload #'key "foo" nil t))
+        (eval-when-compile
+          (declare-function key "foo"))
+        (unless
+            (fboundp 'fun)
+          (autoload #'fun "foo" nil t))
+        (eval-when-compile
+          (declare-function fun "foo"))
+        (add-hook 'hook-hook #'fun)
+        (bind-keys :package foo ("C-a" . key))))))
+
+(ert-deftest use-package-test/:hook-2 ()
+  (match-expansion
+   (use-package foo
+     :hook (hook . fun))
+   `(progn
+      (unless (fboundp 'fun)
+        (autoload #'fun "foo" nil t))
+      (add-hook 'hook-hook #'fun))))
+
+(ert-deftest use-package-test/:hook-3 ()
+  (let ((use-package-hook-name-suffix nil))
+    (match-expansion
+     (use-package foo
+       :hook (hook . fun))
+     `(progn
+        (unless (fboundp 'fun)
+          (autoload #'fun "foo" nil t))
+        (add-hook 'hook #'fun)))))
+
+(ert-deftest use-package-test/:hook-4 ()
+  (let ((use-package-hook-name-suffix "-special"))
+    (match-expansion
+     (use-package foo
+       :hook (hook . fun))
+     `(progn
+        (unless (fboundp 'fun)
+          (autoload #'fun "foo" nil t))
+        (add-hook 'hook-special #'fun)))))
+
+(ert-deftest use-package-test/:hook-5 ()
+  (match-expansion
+   (use-package erefactor
+     :load-path "foo"
+     :after elisp-mode
+     :load t
+     :hook (emacs-lisp-mode
+            . (lambda ()
+                (bind-key "\C-c\C-v" erefactor-map emacs-lisp-mode-map))))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path ,(pred stringp)))
+      (eval-after-load 'elisp-mode
+        '(progn
+           (require 'erefactor nil nil)
+           (add-hook
+            'emacs-lisp-mode-hook
+            #'(lambda nil
+                (bind-key "" erefactor-map emacs-lisp-mode-map))))))))
+
+(ert-deftest use-package-test/:hook-6 ()
+  (match-expansion
+   (use-package erefactor
+     :load-path "foo"
+     :after elisp-mode
+     :hook (emacs-lisp-mode . function))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path ,(pred stringp)))
+      (eval-after-load 'elisp-mode
+        '(progn
+           (unless (fboundp 'function)
+             (autoload #'function "erefactor" nil t))
+           (add-hook 'emacs-lisp-mode-hook #'function))))))
+
+(ert-deftest use-package-test/:hook-7 ()
+  (match-expansion
+   (use-package erefactor
+     :load-path "foo"
+     :after elisp-mode
+     :hook (emacs-lisp-mode . (lambda () (function))))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path ,(pred stringp)))
+      (eval-after-load 'elisp-mode
+        '(progn
+           (require 'erefactor nil nil)
+           (add-hook 'emacs-lisp-mode-hook #'(lambda nil (function))))))))
+
+(ert-deftest use-package-test-normalize/:custom ()
+  (cl-flet ((norm (&rest args)
+                  (apply #'use-package-normalize/:custom
+                         'foopkg :custom args)))
+    (should-error (norm nil))
+    (should-error (norm '(bar)))
+    ;; (should-error (norm '((foo bar baz quux))))
+    (should (equal (norm '(foo bar)) '((foo bar))))
+    ;; (should-error (norm '(foo bar baz)))
+    ;; (should (equal (norm '(foo bar "baz"))
+    ;;                '((foo bar baz))))
+    ))
+
+
+(ert-deftest use-package-test/:custom-1 ()
+  (match-expansion
+   (use-package foo :custom (foo bar))
+   `(progn
+      (let
+          ((custom--inhibit-theme-enable nil))
+        (unless (memq 'use-package custom-known-themes)
+          (deftheme use-package)
+          (enable-theme 'use-package)
+          (setq custom-enabled-themes (remq 'use-package 
custom-enabled-themes)))
+        (custom-theme-set-variables 'use-package
+                                    '(foo bar nil nil "Customized with 
use-package foo")))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:custom-with-comment1 ()
+  (match-expansion
+   (use-package foo :custom (foo bar "commented"))
+   `(progn
+      (let
+          ((custom--inhibit-theme-enable nil))
+        (unless (memq 'use-package custom-known-themes)
+          (deftheme use-package)
+          (enable-theme 'use-package)
+          (setq custom-enabled-themes (remq 'use-package 
custom-enabled-themes)))
+        (custom-theme-set-variables 'use-package
+                                    '(foo bar nil nil "commented")))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:custom-face-1 ()
+  (match-expansion
+   (use-package foo :custom-face (foo ((t (:background "#e4edfc")))))
+   `(progn
+      (apply #'face-spec-set (backquote (foo ((t (:background "#e4edfc"))))))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:custom-face-2 ()
+  (match-expansion
+   (use-package example
+     :custom-face
+     (example-1-face ((t (:foreground "LightPink"))))
+     (example-2-face ((t (:foreground "LightGreen")))))
+   `(progn
+      (apply #'face-spec-set
+             (backquote (example-1-face ((t (:foreground "LightPink"))))))
+      (apply #'face-spec-set
+             (backquote (example-2-face ((t (:foreground "LightGreen"))))))
+      (require 'example nil nil))))
+
+(ert-deftest use-package-test/:custom-face-3 ()
+  (match-expansion
+   (use-package foo :custom-face (foo ((t (:background "#e4edfc"))) 
face-defspec-spec))
+   `(progn
+      (apply #'face-spec-set (backquote (foo ((t (:background "#e4edfc"))) 
face-defspec-spec)))
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:init-1 ()
+  (match-expansion
+   (use-package foo :init (init))
+   `(progn
+      (init)
+      (require 'foo nil nil))))
+
+(ert-deftest use-package-test/:init-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :init (init))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (init)
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:catch-1 ()
+  (match-expansion
+   (use-package foo :catch t)
+   `(progn
+      (defvar ,_
+        #'(lambda (keyword err)
+            (let ((msg (format "%s/%s: %s" 'foo keyword
+                               (error-message-string err))))
+              (display-warning 'use-package msg :error))))
+      (condition-case-unless-debug err
+          (require 'foo nil nil)
+        (error
+         (funcall ,_ :catch err))))))
+
+(ert-deftest use-package-test/:catch-2 ()
+  (match-expansion
+   (use-package foo :catch nil)
+   `(require 'foo nil nil)))
+
+(ert-deftest use-package-test/:catch-3 ()
+  (match-expansion
+   (use-package foo :catch (lambda (keyword error)))
+   `(progn
+      (defvar ,_ (lambda (keyword error)))
+      (condition-case-unless-debug err
+          (require 'foo nil nil)
+        (error
+         (funcall ,_ :catch err))))))
+
+(ert-deftest use-package-test/:after-1 ()
+  (match-expansion
+   (use-package foo :after bar)
+   `(eval-after-load 'bar
+      '(require 'foo nil nil))))
+
+(ert-deftest use-package-test/:after-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :after bar)
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (eval-after-load 'bar
+          '(require 'foo nil nil))))))
+
+(ert-deftest use-package-test/:after-3 ()
+  (match-expansion
+   (use-package foo :after (bar quux))
+   `(eval-after-load 'quux
+      '(eval-after-load 'bar
+         '(require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:after-4 ()
+  (match-expansion
+   (use-package foo :after (:all bar quux))
+   `(eval-after-load 'quux
+      '(eval-after-load 'bar
+         '(require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:after-5 ()
+  (match-expansion
+   (use-package foo :after (:any bar quux))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (require 'foo nil nil)))))
+      (eval-after-load 'bar
+        '(funcall ,_))
+      (eval-after-load 'quux
+        '(funcall ,_)))))
+
+(ert-deftest use-package-test/:after-6 ()
+  (match-expansion
+   (use-package foo :after (:all (:any bar quux) bow))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (require 'foo nil nil)))))
+      (eval-after-load 'bow
+        '(progn
+           (eval-after-load 'bar
+             '(funcall ,_))
+           (eval-after-load 'quux
+             '(funcall ,_)))))))
+
+(ert-deftest use-package-test/:after-7 ()
+  (match-expansion
+   (use-package foo :after (:any (:all bar quux) bow))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (require 'foo nil nil)))))
+      (eval-after-load 'quux
+        '(eval-after-load 'bar
+           '(funcall ,_)))
+      (eval-after-load 'bow
+        '(funcall ,_)))))
+
+(ert-deftest use-package-test/:after-8 ()
+  (match-expansion
+   (use-package foo :after (:all (:any bar quux) (:any bow baz)))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (require 'foo nil nil)))))
+      (eval-after-load 'bow
+        '(progn
+           (eval-after-load 'bar
+             '(funcall ,_))
+           (eval-after-load 'quux
+             '(funcall ,_))))
+      (eval-after-load 'baz
+        '(progn
+           (eval-after-load 'bar
+             '(funcall ,_))
+           (eval-after-load 'quux
+             '(funcall ,_)))))))
+
+(ert-deftest use-package-test/:after-9 ()
+  (match-expansion
+   (use-package foo :after (:any (:all bar quux) (:all bow baz)))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (require 'foo nil nil)))))
+      (eval-after-load 'quux
+        '(eval-after-load 'bar
+           '(funcall ,_)))
+      (eval-after-load 'baz
+        '(eval-after-load 'bow
+           '(funcall ,_))))))
+
+(ert-deftest use-package-test/:after-10 ()
+  (match-expansion
+   (use-package foo :after (:any (:all bar quux) (:any bow baz)))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (require 'foo nil nil)))))
+      (eval-after-load 'quux
+        '(eval-after-load 'bar
+           '(funcall ,_)))
+      (eval-after-load 'bow
+        '(funcall ,_))
+      (eval-after-load 'baz
+        '(funcall ,_)))))
+
+(ert-deftest use-package-test/:demand-1 ()
+  (match-expansion
+   (use-package foo :demand t)
+   `(require 'foo nil nil)))
+
+(ert-deftest use-package-test/:demand-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :demand t)
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (require 'foo nil nil)))))
+
+(ert-deftest use-package-test/:demand-3 ()
+  (match-expansion
+   (use-package foo :demand t :config (config))
+   `(progn
+      (require 'foo nil nil)
+      (config)
+      t)))
+
+(ert-deftest use-package-test/:demand-4 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :demand t :config (config))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (require 'foo nil nil)
+        (config)
+        t))))
+
+(ert-deftest use-package-test/:demand-5 ()
+  ;; #529 - :demand should not override an explicit use of :after
+  (match-expansion
+   (use-package foo :demand t :after bar)
+   `(eval-after-load 'bar
+      '(require 'foo nil nil))))
+
+(ert-deftest use-package-test/:demand-6 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :demand t :after bar)
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (eval-after-load 'bar
+          '(require 'foo nil nil))))))
+
+(ert-deftest use-package-test/:demand-7 ()
+  (match-expansion
+   (use-package counsel
+     :load-path "foo"
+     :after ivy
+     :demand t
+     :diminish
+     :bind (("C-*" . counsel-org-agenda-headlines)
+            ("M-x" . counsel-M-x))
+     :commands (counsel-minibuffer-history
+                counsel-find-library
+                counsel-unicode-char)
+     :preface (preface-code)
+     :init
+     ;; This is actually wrong, but it's just part of the example.
+     (define-key minibuffer-local-map (kbd "M-r")
+       'counsel-minibuffer-history))
+   `(progn
+      (eval-and-compile
+        (add-to-list 'load-path ,(pred stringp)))
+      (eval-and-compile
+        (preface-code))
+      (eval-after-load 'ivy
+        '(progn
+           (define-key minibuffer-local-map (kbd "M-r")
+             'counsel-minibuffer-history)
+           (require 'counsel nil nil)
+           (if (fboundp 'diminish)
+               (diminish 'counsel-mode))
+           (bind-keys :package counsel
+                      ("C-*" . counsel-org-agenda-headlines)
+                      ("M-x" . counsel-M-x)))))))
+
+(ert-deftest use-package-test/:config-1 ()
+  (match-expansion
+   (use-package foo :config (config))
+   `(progn
+      (require 'foo nil nil)
+      (config)
+      t)))
+
+(ert-deftest use-package-test/:config-2 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :config (config))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (require 'foo nil nil)
+        (config)
+        t))))
+
+(ert-deftest use-package-test/:config-3 ()
+  (match-expansion
+   (use-package foo :defer t :config (config))
+   `(eval-after-load 'foo
+      '(progn
+         (config)
+         t))))
+
+(ert-deftest use-package-test/:config-4 ()
+  (let ((byte-compile-current-file t))
+    (match-expansion
+     (use-package foo :defer t :config (config))
+     `(progn
+        (eval-and-compile
+          (eval-when-compile
+            (with-demoted-errors "Cannot load foo: %S" nil
+                                 (unless (featurep 'foo)
+                                   (load "foo" nil t)))))
+        (eval-after-load 'foo
+          '(progn
+             (config)
+             t))))))
+
+(ert-deftest use-package-test-normalize/:diminish ()
+  (should (equal (use-package-normalize-diminish 'foopkg :diminish nil)
+                 '(foopkg-mode)))
+  (should (equal (use-package-normalize-diminish 'foopkg :diminish 'bar)
+                 '(bar)))
+  (should (equal (use-package-normalize-diminish 'foopkg :diminish "bar")
+                 '((foopkg-mode . "bar"))))
+  (should (equal (use-package-normalize-diminish 'foopkg :diminish 'foo-mode)
+                 '(foo-mode)))
+  (should (equal (use-package-normalize-diminish 'foopkg :diminish '(foo . 
"bar"))
+                 '((foo . "bar")))))
+
+(ert-deftest use-package-test/:diminish-1 ()
+  (match-expansion
+   (use-package foo :diminish nil)
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'diminish)
+          (diminish 'foo-mode)))))
+
+(ert-deftest use-package-test/:diminish-2 ()
+  (match-expansion
+   (use-package foo :diminish bar)
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'diminish)
+          (diminish 'bar)))))
+
+(ert-deftest use-package-test/:diminish-3 ()
+  (match-expansion
+   (use-package foo :diminish "bar")
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'diminish)
+          (diminish 'foo-mode "bar")))))
+
+(ert-deftest use-package-test/:diminish-4 ()
+  (match-expansion
+   (use-package foo :diminish (foo . "bar"))
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'diminish)
+          (diminish 'foo "bar")))))
+
+(ert-deftest use-package-test-normalize/:delight ()
+  (should (equal `((foo-mode nil foo))
+                 (use-package-normalize/:delight 'foo :delight nil)))
+  (should (equal `((foo-mode nil foo-mode))
+                 (use-package-normalize/:delight 'foo-mode :delight nil)))
+  (should (equal `((bar-mode nil foo))
+                 (use-package-normalize/:delight 'foo :delight '(bar-mode))))
+  (should (equal `((bar-mode nil :major))
+                 (use-package-normalize/:delight 'foo :delight '((bar-mode nil 
:major)))))
+  (should (equal `((foo-mode "abc" foo))
+                 (use-package-normalize/:delight 'foo :delight '("abc"))))
+  (should (equal `((foo-mode (:eval 1) foo))
+                 (use-package-normalize/:delight 'foo :delight '('(:eval 1)))))
+  (should (equal (use-package-normalize/:delight 'foo :delight '((a-mode) 
(b-mode " b")))
+                 `((a-mode nil foo) (b-mode " b" foo))))
+  (should-error (use-package-normalize/:delight 'foo :delight '((:eval 1)))))
+
+(ert-deftest use-package-test/:delight-1 ()
+  (match-expansion
+   (use-package foo :delight)
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'delight)
+          (delight '((foo-mode nil foo)))))))
+
+(ert-deftest use-package-test/:delight-2 ()
+  (should-error
+   (match-expansion
+    (use-package foo :delight nil)
+    `(progn
+       (require 'foo nil nil)
+       (if (fboundp 'diminish)
+           (diminish 'foo-mode))))))
+
+(ert-deftest use-package-test/:delight-3 ()
+  (match-expansion
+   (use-package foo :delight bar)
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'delight)
+          (delight '((bar nil foo)))))))
+
+(ert-deftest use-package-test/:delight-4 ()
+  (match-expansion
+   (use-package foo :delight "bar")
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'delight)
+          (delight '((foo-mode "bar" foo)))))))
+
+(ert-deftest use-package-test/:delight-5 ()
+  (should-error
+   (match-expansion
+    (use-package foo :delight (foo . "bar"))
+    `(progn
+       (require 'foo nil nil)
+       (if (fboundp 'diminish)
+           (diminish 'foo "bar"))))))
+
+(ert-deftest use-package-test/:delight-6 ()
+  (match-expansion
+   (use-package foo :delight (foo "bar"))
+   `(progn
+      (require 'foo nil nil)
+      (if (fboundp 'delight)
+          (delight '((foo "bar" foo)))))))
+
+(ert-deftest use-package-test/334-1 ()
+  (let (foo1-map foo2-map
+                 bar1-func1
+                 bar1-func2
+                 bar2-func1
+                 bar2-func2
+                 bar3-func1
+                 bar3-func2
+                 bar4-func1
+                 bar4-func2)
+    (match-expansion
+     (bind-keys :map foo1-map
+                ("Y" . foo1)
+                :prefix "y"
+                :prefix-map bar1-prefix-map
+                ("y" . bar1-func1)
+                ("f" . bar1-func2)
+                :prefix "y"
+                :prefix-map bar2-prefix-map
+                ("y" . bar2-func1)
+                ("f" . bar2-func2)
+                :map foo2-map
+                ("Y" . foo2)
+                :prefix "y"
+                :prefix-map bar3-prefix-map
+                ("y" . bar3-func1)
+                ("f" . bar3-func2)
+                :prefix "y"
+                :prefix-map bar4-prefix-map
+                ("y" . bar4-func1)
+                ("f" . bar4-func2))
+     `(progn
+        (bind-key "Y" #'foo1 foo1-map nil)
+        (defvar bar1-prefix-map)
+        (define-prefix-command 'bar1-prefix-map)
+        (bind-key "y" 'bar1-prefix-map foo1-map nil)
+        (bind-key "y" #'bar1-func1 bar1-prefix-map nil)
+        (bind-key "f" #'bar1-func2 bar1-prefix-map nil)
+        (defvar bar2-prefix-map)
+        (define-prefix-command 'bar2-prefix-map)
+        (bind-key "y" 'bar2-prefix-map foo1-map nil)
+        (bind-key "y" #'bar2-func1 bar2-prefix-map nil)
+        (bind-key "f" #'bar2-func2 bar2-prefix-map nil)
+        (bind-key "Y" #'foo2 foo2-map nil)
+        (defvar bar3-prefix-map)
+        (define-prefix-command 'bar3-prefix-map)
+        (bind-key "y" 'bar3-prefix-map foo2-map nil)
+        (bind-key "y" #'bar3-func1 bar3-prefix-map nil)
+        (bind-key "f" #'bar3-func2 bar3-prefix-map nil)
+        (defvar bar4-prefix-map)
+        (define-prefix-command 'bar4-prefix-map)
+        (bind-key "y" 'bar4-prefix-map foo2-map nil)
+        (bind-key "y" #'bar4-func1 bar4-prefix-map nil)
+        (bind-key "f" #'bar4-func2 bar4-prefix-map nil)))))
+
+(ert-deftest use-package-test/334-2 ()
+  (let (w3m-lnum-mode-map
+        w3m-print-current-url
+        w3m-lnum-print-this-url
+        w3m-print-this-url)
+    (match-expansion
+     (bind-keys :map w3m-lnum-mode-map
+                :prefix "y"
+                :prefix-map w3m-y-prefix-map
+                ("y" . w3m-print-current-url)
+                ("f" . w3m-lnum-print-this-url)
+                ("t" . w3m-print-this-url))
+     `(progn
+        (defvar w3m-y-prefix-map)
+        (define-prefix-command 'w3m-y-prefix-map)
+        (bind-key "y" 'w3m-y-prefix-map w3m-lnum-mode-map nil)
+        (bind-key "y" #'w3m-print-current-url w3m-y-prefix-map nil)
+        (bind-key "f" #'w3m-lnum-print-this-url w3m-y-prefix-map nil)
+        (bind-key "t" #'w3m-print-this-url w3m-y-prefix-map nil)))))
+
+(ert-deftest use-package-test/482-1 ()
+  (match-expansion
+   (use-package simple
+     :bind-keymap ("C-t " . my/transpose-map)
+     :bind (:map my/transpose-map
+                ("w" . transpose-words)))
+   `(progn
+      (unless (fboundp 'transpose-words)
+        (autoload #'transpose-words "simple" nil t))
+      (bind-key "C-t "
+                #'(lambda nil
+                    (interactive)
+                    (use-package-autoload-keymap 'my/transpose-map 'simple 
nil)))
+      (bind-keys :package simple :map my/transpose-map
+                 ("w" . transpose-words)))))
+
+(ert-deftest use-package-test/482-2 ()
+  (match-expansion
+   (use-package simple
+     :bind (:prefix-map my/transpose-map
+                        :prefix "C-t"
+                        ("w" . transpose-words)))
+   `(progn
+      (unless (fboundp 'transpose-words)
+        (autoload #'transpose-words "simple" nil t))
+      (bind-keys :package simple
+                 :prefix-map my/transpose-map
+                 :prefix "C-t"
+                 ("w" . transpose-words)))))
+
+(ert-deftest use-package-test/482-3 ()
+  (match-expansion
+   (bind-keys :package simple
+              :prefix-map my/transpose-map
+              :prefix "C-t"
+              ("w" . transpose-words))
+   `(progn
+      (defvar my/transpose-map)
+      (define-prefix-command 'my/transpose-map)
+      (bind-key "C-t" 'my/transpose-map nil nil)
+      (bind-key "w" #'transpose-words my/transpose-map nil))))
+
+(ert-deftest use-package-test/538 ()
+  (match-expansion
+   (use-package mu4e
+     :commands (mu4e)
+     :bind (("<f9>" . mu4e))
+     :init
+     :config
+     (config))
+   `(progn
+      (unless (fboundp 'mu4e)
+        (autoload #'mu4e "mu4e" nil t))
+      (eval-after-load 'mu4e
+        '(progn (config) t))
+      (bind-keys :package mu4e ("<f9>" . mu4e)))))
+
+(ert-deftest use-package-test/543 ()
+  (match-expansion
+   (use-package hydra
+     :ensure)
+   `(progn
+      (use-package-ensure-elpa 'hydra '(t) 'nil)
+      (require 'hydra nil nil))))
+
+(ert-deftest use-package-test/545 ()
+  (match-expansion
+   (use-package spacemacs-theme
+     :ensure t
+     :init                                 ; or :config
+     (load-theme 'spacemacs-dark t)
+     )
+   `(progn
+      (use-package-ensure-elpa 'spacemacs-theme '(t) 'nil)
+      (load-theme 'spacemacs-dark t)
+      (require 'spacemacs-theme nil nil))
+   ))
+
+(ert-deftest use-package-test/550 ()
+  (match-expansion
+   (use-package company-try-hard
+     :ensure t
+     :bind
+     ("C-c M-/" . company-try-hard)
+     (:map company-active-map
+           ("C-c M-/" . company-try-hard)))
+   `(progn
+      (use-package-ensure-elpa 'company-try-hard
+                               '(t)
+                               'nil)
+      (unless
+          (fboundp 'company-try-hard)
+        (autoload #'company-try-hard "company-try-hard" nil t))
+      (bind-keys :package company-try-hard
+                 ("C-c M-/" . company-try-hard)
+                 :map company-active-map
+                 ("C-c M-/" . company-try-hard)))))
+
+(ert-deftest use-package-test/558 ()
+  (match-expansion
+   (bind-keys* :package org-ref
+               ("C-c C-r" . org-ref-helm-insert-cite-link))
+   `(bind-key "C-c C-r" #'org-ref-helm-insert-cite-link override-global-map 
nil)))
+
+(ert-deftest use-package-test/560 ()
+  (cl-letf (((symbol-function #'executable-find) #'ignore))
+    (let (notmuch-command)
+      (match-expansion
+       (use-package notmuch
+         :preface (setq-default notmuch-command (executable-find "notmuch"))
+         :if notmuch-command
+         :requires foo
+         :load-path "foo"
+         :defines var)
+       `(progn
+          (eval-and-compile
+            (add-to-list 'load-path ,(pred stringp)))
+          (when (featurep 'foo)
+            (eval-and-compile
+              (setq-default notmuch-command
+                            (executable-find "notmuch")))
+            (when (symbol-value 'notmuch-command)
+              (require 'notmuch nil nil))))))))
+
+(ert-deftest use-package-test/572-1 ()
+  (let ((use-package-always-defer t))
+    (match-expansion
+     (use-package auth-password-store
+       :after auth-source
+       :init
+       (setq auth-sources '(password-store)))
+     `(eval-after-load 'auth-source
+        '(setq auth-sources '(password-store))))))
+
+(ert-deftest use-package-test/572-2 ()
+  (let ((use-package-always-defer t))
+    (match-expansion
+     (use-package ivy-hydra :after ivy)
+     `nil)))
+
+(ert-deftest use-package-test/572-3 ()
+  (let ((use-package-always-defer t)
+        (use-package-defaults
+         (let ((defaults (copy-alist use-package-defaults)))
+           (setcdr (assq :defer defaults)
+                   '(use-package-always-defer
+                     (lambda (name args)
+                       (and use-package-always-defer
+                            (not (plist-member args :after))
+                            (not (plist-member args :defer))
+                            (not (plist-member args :demand))))))
+           defaults)))
+    (match-expansion
+     (use-package ivy-hydra :after ivy)
+     `(eval-after-load 'ivy
+        '(require 'ivy-hydra nil nil)))))
+
+(ert-deftest use-package-test/575-1 ()
+  (match-expansion
+   (use-package helm
+     :defer t
+     :after (:any ido dired)
+     :config
+     (message "test. helm start"))
+   `(progn
+      (defvar ,_ nil)
+      (defvar ,_ nil)
+      (defvar ,_
+        #'(lambda nil
+            (if ,_ ,_
+              (setq ,_ t ,_
+                    (eval-after-load 'helm
+                      '(progn
+                         (message "test. helm start")
+                         t))))))
+      (eval-after-load 'ido
+        '(funcall ,_))
+      (eval-after-load 'dired
+        '(funcall ,_)))))
+
+(ert-deftest use-package-test/575-2 ()
+  (match-expansion
+   (use-package helm
+     :defer t
+     :bind ("C-c d" . helm-mini)
+     :config
+     (message "test. helm start"))
+   `(progn
+      (unless (fboundp 'helm-mini)
+        (autoload #'helm-mini "helm" nil t))
+      (eval-after-load 'helm
+        '(progn
+           (message "test. helm start")
+           t))
+      (bind-keys :package helm ("C-c d" . helm-mini)))))
+
+(ert-deftest use-package-test/585 ()
+  (match-expansion
+   (use-package bug
+     :bind (:map bug-map ("C-a" . alpha))
+     :bind (("C-b" . beta)))
+   `(progn
+      (unless (fboundp 'alpha)
+        (autoload #'alpha "bug" nil t))
+      (unless (fboundp 'beta)
+        (autoload #'beta "bug" nil t))
+      (bind-keys :package bug :map bug-map
+                 ("C-a" . alpha))
+      (bind-keys :package bug
+                 ("C-b" . beta)))))
+
+(ert-deftest use-package-test/589 ()
+  (let ((use-package-verbose t)
+        (use-package-expand-minimally t)
+        debug-on-error
+        warnings)
+    (cl-letf (((symbol-function #'display-warning)
+               (lambda (_ msg _) (push msg warnings))))
+      (progn
+        (macroexpand-1
+         '(use-package ediff :defer t (setq my-var t)))
+        (should (= (and (> (length warnings) 0)
+                        (string-match ":defer wants exactly one argument"
+                                      (car warnings))) 44))))))
+
+(ert-deftest use-package-test/591 ()
+  (let ((use-package-defaults
+         (cons '(:if (lambda (name _) `(locate-library ,name)) t)
+               use-package-defaults)))
+    (match-expansion
+     (use-package nonexistent
+       :hook lisp-mode)
+     `(when (locate-library nonexistent)
+        (unless (fboundp 'nonexistent-mode)
+          (autoload #'nonexistent-mode "nonexistent" nil t))
+        (add-hook 'lisp-mode-hook #'nonexistent-mode)))))
+
+(ert-deftest bind-key/:prefix-map ()
+  (match-expansion
+   (bind-keys :prefix "<f1>"
+              :prefix-map my/map)
+   `(progn
+      (defvar my/map)
+      (define-prefix-command 'my/map)
+      (bind-key "<f1>" 'my/map nil nil))))
+
+
+(ert-deftest bind-key/845 ()
+  (defvar test-map (make-keymap))
+  (bind-key "<f1>" 'ignore 'test-map)
+  (should (eq (lookup-key test-map (kbd "<f1>")) 'ignore))
+  (let ((binding (cl-find "<f1>" personal-keybindings :test 'string= :key 
'caar)))
+    (message "test-map %s" test-map)
+    (message "binding %s" binding)
+    (should (eq (cdar binding) 'test-map))
+    (should (eq (nth 1 binding) 'ignore))
+    (should (eq (nth 2 binding) nil))))
+
+;; Local Variables:
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; End:
+
+;;; use-package-tests.el ends here
diff --git a/test/manual/noverlay/itree-tests.c 
b/test/manual/noverlay/itree-tests.c
index 278e65f9bf..8cab7bf84d 100644
--- a/test/manual/noverlay/itree-tests.c
+++ b/test/manual/noverlay/itree-tests.c
@@ -26,7 +26,6 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #include "emacs-compat.h"
 
 #define EMACS_LISP_H            /* lisp.h inclusion guard */
-#define ITREE_DEBUG 1
 #define ITREE_TESTING
 #include "itree.c"
 
@@ -53,7 +52,7 @@ test_insert1_setup (void)
   enum { N = 6 };
   const int values[N] = {50, 30, 20, 10, 15, 5};
   struct itree_node *nodes[N] = {&N_50, &N_30, &N_20, &N_10, &N_15, &N_05};
-  interval_tree_init (&tree);
+  itree_init (&tree);
   for (int i = 0; i < N; ++i)
     {
       nodes[i]->begin = nodes[i]->end = values[i];
@@ -67,7 +66,7 @@ START_TEST (test_insert_1)
    *                 [50]
    */
 
-  interval_tree_insert (&tree, &N_50);
+  itree_insert_node (&tree, &N_50);
   ck_assert (! N_50.red);
   ck_assert_ptr_eq (&N_50, tree.root);
 }
@@ -81,8 +80,8 @@ START_TEST (test_insert_2)
    *              (30)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_30);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_30);
   ck_assert (! N_50.red);
   ck_assert (N_30.red);
   ck_assert_ptr_eq (&N_50, tree.root);
@@ -102,9 +101,9 @@ START_TEST (test_insert_3)
    *             (20)   (50)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_30);
-  interval_tree_insert (&tree, &N_20);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_30);
+  itree_insert_node (&tree, &N_20);
   ck_assert (N_50.red);
   ck_assert (! N_30.red);
   ck_assert (N_20.red);
@@ -128,10 +127,10 @@ START_TEST (test_insert_4)
    *           (10)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_30);
-  interval_tree_insert (&tree, &N_20);
-  interval_tree_insert (&tree, &N_10);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_30);
+  itree_insert_node (&tree, &N_20);
+  itree_insert_node (&tree, &N_10);
   ck_assert (! N_50.red);
   ck_assert (! N_30.red);
   ck_assert (! N_20.red);
@@ -159,11 +158,11 @@ START_TEST (test_insert_5)
    *           (10) (20)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_30);
-  interval_tree_insert (&tree, &N_20);
-  interval_tree_insert (&tree, &N_10);
-  interval_tree_insert (&tree, &N_15);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_30);
+  itree_insert_node (&tree, &N_20);
+  itree_insert_node (&tree, &N_10);
+  itree_insert_node (&tree, &N_15);
   ck_assert (! N_50.red);
   ck_assert (! N_30.red);
   ck_assert (N_20.red);
@@ -197,12 +196,12 @@ START_TEST (test_insert_6)
    *         (5)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_30);
-  interval_tree_insert (&tree, &N_20);
-  interval_tree_insert (&tree, &N_10);
-  interval_tree_insert (&tree, &N_15);
-  interval_tree_insert (&tree, &N_05);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_30);
+  itree_insert_node (&tree, &N_20);
+  itree_insert_node (&tree, &N_10);
+  itree_insert_node (&tree, &N_15);
+  itree_insert_node (&tree, &N_05);
   ck_assert (! N_50.red);
   ck_assert (! N_30.red);
   ck_assert (! N_20.red);
@@ -238,7 +237,7 @@ test_insert2_setup (void)
   enum { N = 6 };
   const int values[] = {50, 70, 80, 90, 85, 95};
   struct itree_node *nodes[N] = {&N_50, &N_70, &N_80, &N_90, &N_85, &N_95};
-  interval_tree_init (&tree);
+  itree_init (&tree);
   for (int i = 0; i < N; ++i)
     {
       nodes[i]->begin = nodes[i]->end = values[i];
@@ -252,7 +251,7 @@ START_TEST (test_insert_7)
    *                 [50]
    */
 
-  interval_tree_insert (&tree, &N_50);
+  itree_insert_node (&tree, &N_50);
   ck_assert (! N_50.red);
   ck_assert_ptr_eq (&N_50, tree.root);
 }
@@ -266,8 +265,8 @@ START_TEST (test_insert_8)
    *                   (70)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_70);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_70);
   ck_assert (! N_50.red);
   ck_assert (N_70.red);
   ck_assert_ptr_eq (&N_50, tree.root);
@@ -287,9 +286,9 @@ START_TEST (test_insert_9)
    *             (50)   (80)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_70);
-  interval_tree_insert (&tree, &N_80);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_70);
+  itree_insert_node (&tree, &N_80);
   ck_assert (N_50.red);
   ck_assert (! N_70.red);
   ck_assert (N_80.red);
@@ -313,10 +312,10 @@ START_TEST (test_insert_10)
    *                      (90)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_70);
-  interval_tree_insert (&tree, &N_80);
-  interval_tree_insert (&tree, &N_90);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_70);
+  itree_insert_node (&tree, &N_80);
+  itree_insert_node (&tree, &N_90);
   ck_assert (! N_50.red);
   ck_assert (! N_70.red);
   ck_assert (! N_80.red);
@@ -344,11 +343,11 @@ START_TEST (test_insert_11)
    *                  (80) (90)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_70);
-  interval_tree_insert (&tree, &N_80);
-  interval_tree_insert (&tree, &N_90);
-  interval_tree_insert (&tree, &N_85);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_70);
+  itree_insert_node (&tree, &N_80);
+  itree_insert_node (&tree, &N_90);
+  itree_insert_node (&tree, &N_85);
   ck_assert (! N_50.red);
   ck_assert (! N_70.red);
   ck_assert (N_80.red);
@@ -383,12 +382,12 @@ START_TEST (test_insert_12)
    *                        (95)
    */
 
-  interval_tree_insert (&tree, &N_50);
-  interval_tree_insert (&tree, &N_70);
-  interval_tree_insert (&tree, &N_80);
-  interval_tree_insert (&tree, &N_90);
-  interval_tree_insert (&tree, &N_85);
-  interval_tree_insert (&tree, &N_95);
+  itree_insert_node (&tree, &N_50);
+  itree_insert_node (&tree, &N_70);
+  itree_insert_node (&tree, &N_80);
+  itree_insert_node (&tree, &N_90);
+  itree_insert_node (&tree, &N_85);
+  itree_insert_node (&tree, &N_95);
   ck_assert (! N_50.red);
   ck_assert (! N_70.red);
   ck_assert (! N_80.red);
@@ -419,7 +418,7 @@ START_TEST (test_insert_13)
   enum { N = 4 };
   const int values[N] = {10, 20, 30, 40};
   struct itree_node *nodes[N] = {&N_10, &N_20, &N_30, &N_40};
-  interval_tree_init (&tree);
+  itree_init (&tree);
   for (int i = 0; i < N; ++i)
     itree_insert (&tree, nodes[i], values[i], values[i]);
 
@@ -437,13 +436,13 @@ END_TEST
 START_TEST (test_insert_14)
 {
   enum { N = 3 };
-  struct itree_node nodes[N];
-  interval_tree_init (&tree);
+  struct itree_node nodes[N] = {0};
+  itree_init (&tree);
 
   for (int i = 0; i < N; ++i)
     itree_insert (&tree, &nodes[i], 10, 10);
   for (int i = 0; i < N; ++i)
-    ck_assert (interval_tree_contains (&tree, &nodes[i]));
+    ck_assert (itree_contains (&tree, &nodes[i]));
 }
 END_TEST
 
@@ -458,7 +457,7 @@ END_TEST
 static void
 test_remove1_setup (void)
 {
-  interval_tree_init (&tree);
+  itree_init (&tree);
   tree.root = &B;
   A.parent = &B; B.parent = NULL; C.parent = &D; D.parent = &B; E.parent = &D;
   A.left = A.right = C.left = C.right = E.left = E.right = NULL;
@@ -480,7 +479,7 @@ START_TEST (test_remove_1)
 {
   B.red = A.red = C.red = E.red = false;
   D.red = true;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -502,7 +501,7 @@ END_TEST
 START_TEST (test_remove_2)
 {
   B.red = D.red = A.red = C.red = E.red = false;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -523,7 +522,7 @@ START_TEST (test_remove_3)
 {
   D.red = A.red = E.red = false;
   B.red = C.red = true;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -546,7 +545,7 @@ START_TEST (test_remove_4)
 {
   B.red = C.red = E.red = true;
   A.red = D.red = false;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -569,7 +568,7 @@ END_TEST
 static void
 test_remove2_setup (void)
 {
-  interval_tree_init (&tree);
+  itree_init (&tree);
   tree.root = &B;
   A.parent = &B; B.parent = NULL; C.parent = &D; D.parent = &B; E.parent = &D;
   A.right = A.left = C.right = C.left = E.right = E.left = NULL;
@@ -589,7 +588,7 @@ START_TEST (test_remove_5)
 {
   B.red = A.red = C.red = E.red = false;
   D.red = true;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -611,7 +610,7 @@ END_TEST
 START_TEST (test_remove_6)
 {
   B.red = D.red = A.red = C.red = E.red = false;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -632,7 +631,7 @@ START_TEST (test_remove_7)
 {
   D.red = A.red = E.red = false;
   B.red = C.red = true;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -655,7 +654,7 @@ START_TEST (test_remove_8)
 {
   B.red = C.red = E.red = true;
   A.red = D.red = false;
-  interval_tree_remove_fix (&tree, &A, &B);
+  itree_remove_fix (&tree, &A, &B);
 
   ck_assert (! A.red);
   ck_assert (! B.red);
@@ -676,7 +675,7 @@ START_TEST (test_remove_9)
   enum { N = 4 };
   const int values[N] = {10, 20, 30, 40};
   struct itree_node *nodes[N] = {&N_10, &N_20, &N_30, &N_40};
-  interval_tree_init (&tree);
+  itree_init (&tree);
   for (int i = 0; i < N; ++i)
     itree_insert (&tree, nodes[i], values[i], values[i]);
 
@@ -722,8 +721,8 @@ START_TEST (test_remove_10)
   srand (42);
   shuffle (index, N);
 
-  interval_tree_init (&tree);
-  struct itree_node nodes[N];
+  itree_init (&tree);
+  struct itree_node nodes[N] = {0};
   for (int i = 0; i < N; ++i)
     {
       ptrdiff_t pos = (i + 1) * 10;
@@ -733,10 +732,10 @@ START_TEST (test_remove_10)
   shuffle (index, N);
   for (int i = 0; i < N; ++i)
     {
-      ck_assert (interval_tree_contains (&tree, &nodes[index[i]]));
+      ck_assert (itree_contains (&tree, &nodes[index[i]]));
       itree_remove (&tree, &nodes[index[i]]);
     }
-  ck_assert_ptr_null (tree.root);
+  ck_assert (itree_empty_p (&tree));
   ck_assert_int_eq (tree.size, 0);
 }
 END_TEST
@@ -748,12 +747,12 @@ END_TEST
 
 START_TEST (test_generator_1)
 {
-  struct itree_node node, *n;
-  struct itree_iterator *g;
-  interval_tree_init (&tree);
+  struct itree_node node = {0}, *n;
+  struct itree_iterator it, *g;
+  itree_init (&tree);
 
   itree_insert (&tree, &node, 10, 20);
-  g = itree_iterator_start (&tree, 0, 30, ITREE_ASCENDING, NULL, 0);
+  g = itree_iterator_start (&it, &tree, 0, 30, ITREE_ASCENDING);
   n = itree_iterator_next (g);
   ck_assert_ptr_eq (n, &node);
   ck_assert_int_eq (n->begin, 10);
@@ -761,13 +760,11 @@ START_TEST (test_generator_1)
   ck_assert_ptr_null (itree_iterator_next (g));
   ck_assert_ptr_null (itree_iterator_next (g));
   ck_assert_ptr_null (itree_iterator_next (g));
-  itree_iterator_finish (g);
 
-  g = itree_iterator_start (&tree, 30, 50, ITREE_ASCENDING, NULL, 0);
+  g = itree_iterator_start (&it, &tree, 30, 50, ITREE_ASCENDING);
   ck_assert_ptr_null (itree_iterator_next (g));
   ck_assert_ptr_null (itree_iterator_next (g));
   ck_assert_ptr_null (itree_iterator_next (g));
-  itree_iterator_finish (g);
 }
 END_TEST
 
@@ -777,8 +774,8 @@ test_check_generator (struct itree_tree *tree,
                       int n, ...)
 {
   va_list ap;
-  struct itree_iterator *g =
-    itree_iterator_start (tree, begin, end, ITREE_ASCENDING, NULL, 0);
+  struct itree_iterator it, *g =
+    itree_iterator_start (&it, tree, begin, end, ITREE_ASCENDING);
 
   va_start (ap, n);
   for (int i = 0; i < n; ++i)
@@ -790,13 +787,12 @@ test_check_generator (struct itree_tree *tree,
   va_end (ap);
   ck_assert_ptr_null (itree_iterator_next (g));
   ck_assert_ptr_null (itree_iterator_next (g));
-  itree_iterator_finish (g);
 }
 
 START_TEST (test_generator_2)
 {
-  interval_tree_init (&tree);
-  struct itree_node nodes[3];
+  itree_init (&tree);
+  struct itree_node nodes[3] = {0};
   for (int i = 0; i < 3; ++i)
     itree_insert (&tree, &nodes[i], 10 * (i + 1), 10 * (i + 2));
 
@@ -830,7 +826,7 @@ test_create_tree (struct itree_node *nodes, int n, bool 
doshuffle)
       shuffle (index, n);
     }
 
-  interval_tree_init (&tree);
+  itree_init (&tree);
   for (int i = 0; i < n; ++i)
     {
       struct itree_node *node = &nodes[index[i]];
@@ -862,8 +858,8 @@ START_TEST (test_generator_5)
                                 {.begin = 30, .end = 50},
                                 {.begin = 40, .end = 60}};
   test_create_tree (nodes, N, false);
-  struct itree_iterator *g =
-    itree_iterator_start (&tree, 0, 100, ITREE_PRE_ORDER, NULL, 0);
+  struct itree_iterator it, *g =
+    itree_iterator_start (&it, &tree, 0, 100, ITREE_PRE_ORDER);
   for (int i = 0; i < N; ++i)
     {
       struct itree_node *n = itree_iterator_next (g);
@@ -876,7 +872,6 @@ START_TEST (test_generator_5)
         case 3: ck_assert_int_eq (40, n->begin); break;
         }
     }
-  itree_iterator_finish (g);
 }
 END_TEST
 
@@ -888,8 +883,8 @@ START_TEST (test_generator_6)
                                 {.begin = 30, .end = 50},
                                 {.begin = 40, .end = 60}};
   test_create_tree (nodes, N, true);
-  struct itree_iterator *g =
-    itree_iterator_start (&tree, 0, 100, ITREE_ASCENDING, NULL, 0);
+  struct itree_iterator it, *g =
+    itree_iterator_start (&it, &tree, 0, 100, ITREE_ASCENDING);
   for (int i = 0; i < N; ++i)
     {
       struct itree_node *n = itree_iterator_next (g);
@@ -902,7 +897,6 @@ START_TEST (test_generator_6)
         case 3: ck_assert_int_eq (40, n->begin); break;
         }
     }
-  itree_iterator_finish (g);
 }
 END_TEST
 
@@ -914,8 +908,8 @@ START_TEST (test_generator_7)
                                 {.begin = 30, .end = 50},
                                 {.begin = 40, .end = 60}};
   test_create_tree (nodes, N, true);
-  struct itree_iterator *g =
-    itree_iterator_start (&tree, 0, 100, ITREE_DESCENDING, NULL, 0);
+  struct itree_iterator it, *g =
+    itree_iterator_start (&it, &tree, 0, 100, ITREE_DESCENDING);
   for (int i = 0; i < N; ++i)
     {
       struct itree_node *n = itree_iterator_next (g);
@@ -928,7 +922,6 @@ START_TEST (test_generator_7)
         case 3: ck_assert_int_eq (10, n->begin); break;
         }
     }
-  itree_iterator_finish (g);
 }
 END_TEST
 
@@ -938,14 +931,13 @@ START_TEST (test_generator_8)
   struct itree_node nodes[N] = {{.begin = 20, .end = 30},
                                 {.begin = 40, .end = 50}};
   test_create_tree (nodes, N, false);
-  struct itree_iterator *g =
-    itree_iterator_start (&tree, 1, 60, ITREE_DESCENDING, NULL, 0);
+  struct itree_iterator it, *g =
+    itree_iterator_start (&it, &tree, 1, 60, ITREE_DESCENDING);
   struct itree_node *n = itree_iterator_next (g);
   ck_assert_int_eq (n->begin, 40);
   itree_iterator_narrow (g, 50, 60);
   n = itree_iterator_next (g);
   ck_assert_ptr_null (n);
-  itree_iterator_finish (g);
 }
 END_TEST
 
@@ -955,14 +947,13 @@ START_TEST (test_generator_9)
   struct itree_node nodes[N] = {{.begin = 25, .end = 25},
                                 {.begin = 20, .end = 30}};
   test_create_tree (nodes, N, false);
-  struct itree_iterator *g =
-    itree_iterator_start (&tree, 1, 30, ITREE_DESCENDING, NULL, 0);
+  struct itree_iterator it, *g =
+    itree_iterator_start (&it, &tree, 1, 30, ITREE_DESCENDING);
   struct itree_node *n = itree_iterator_next (g);
   ck_assert_int_eq (n->begin, 25);
   itree_iterator_narrow (g, 25, 30);
   n = itree_iterator_next (g);
   ck_assert_int_eq (n->begin, 20);
-  itree_iterator_finish (g);
 }
 END_TEST
 
@@ -981,7 +972,7 @@ static void
 test_setup_gap_node (ptrdiff_t begin, ptrdiff_t end,
                      bool front_advance, bool rear_advance)
 {
-  interval_tree_init (&gap_tree);
+  itree_init (&gap_tree);
   gap_node.front_advance = front_advance;
   gap_node.rear_advance = rear_advance;
   itree_insert (&gap_tree, &gap_node, begin, end);
@@ -1281,9 +1272,8 @@ main (void)
   Suite *s = basic_suite ();
   SRunner *sr = srunner_create (s);
 
-  init_itree ();
   srunner_run_all (sr, CK_ENV);
-  int nfailed = srunner_ntests_failed (sr);
+  int failed = srunner_ntests_failed (sr);
   srunner_free (sr);
-  return (nfailed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+  return failed ? EXIT_FAILURE : EXIT_SUCCESS;
 }
diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el
index e9ddf9c0be..a2472c43da 100644
--- a/test/src/sqlite-tests.el
+++ b/test/src/sqlite-tests.el
@@ -36,6 +36,7 @@
 (declare-function sqlite-select "sqlite.c")
 (declare-function sqlite-open "sqlite.c")
 (declare-function sqlite-load-extension "sqlite.c")
+(declare-function sqlite-version "sqlite.c")
 
 (ert-deftest sqlite-select ()
   (skip-unless (sqlite-available-p))
diff --git a/test/src/treesit-tests.el b/test/src/treesit-tests.el
index 80fde408cd..48b61cf3dc 100644
--- a/test/src/treesit-tests.el
+++ b/test/src/treesit-tests.el
@@ -54,6 +54,7 @@
 (declare-function treesit-node-descendant-for-range "treesit.c")
 (declare-function treesit-node-eq "treesit.c")
 
+;;; Basic API
 
 (ert-deftest treesit-basic-parsing ()
   "Test basic parsing routines."
@@ -143,6 +144,8 @@
                      (treesit-node-string
                       (treesit-node-first-child-for-pos
                        doc-node 3))))
+      (should-error (treesit-node-first-child-for-pos doc-node 100)
+                    :type 'args-out-of-range)
       ;; `treesit-node-descendant-for-range'.
       (should (equal "(\"{\")"
                      (treesit-node-string
@@ -152,10 +155,186 @@
                      (treesit-node-string
                       (treesit-node-descendant-for-range
                        root-node 6 7 t))))
+      (should-error (treesit-node-descendant-for-range
+                     root-node 100 101)
+                    :type 'args-out-of-range)
       ;; `treesit-node-eq'.
       (should (treesit-node-eq root-node root-node))
       (should (not (treesit-node-eq root-node doc-node))))))
 
+;;; Indirect buffer
+
+(ert-deftest treesit-indirect-buffer ()
+  "Tests for indirect buffers."
+  (skip-unless (treesit-language-available-p 'json))
+  (let ((base (get-buffer-create "*treesit test*"))
+        parser indirect)
+    (unwind-protect
+        (progn
+          (with-current-buffer base
+            (setq indirect (clone-indirect-buffer "*treesit test 1*" nil)))
+          (with-current-buffer indirect
+            (setq parser (treesit-parser-create 'json)))
+          ;; 1. Parser created in the indirect buffer should be
+          ;; actually be created in the base buffer.
+          (with-current-buffer base
+            (should (equal (list parser)
+                           (treesit-parser-list)))
+            (insert "[1,2,3]"))
+          ;; Change in the base buffer should be reflected in the
+          ;; indirect buffer.
+          (with-current-buffer indirect
+            (should (eq (treesit-node-end
+                         (treesit-buffer-root-node))
+                        8))
+            (erase-buffer))
+          ;; Change in the indirect buffer should be reflected in the
+          ;; base buffer.
+          (with-current-buffer base
+            (should (eq (treesit-node-end
+                         (treesit-buffer-root-node))
+                        1))
+            (erase-buffer)))
+      (kill-buffer base)
+      (kill-buffer indirect))))
+
+;;; Tree traversal
+
+(ert-deftest treesit-search-subtree ()
+  "Test `treesit-search-subtree'."
+  (skip-unless (treesit-language-available-p 'json))
+  (with-temp-buffer
+    (let (parser root array)
+      (progn
+        (insert "[[1,2,3], [1,2,3], [1,2,3]]")
+        (setq parser (treesit-parser-create 'json))
+        (setq root (treesit-parser-root-node parser))
+        (setq array (treesit-node-child root 0)))
+      (dolist (subarray (treesit-node-children array t))
+        ;; Find named node forward.
+        (should (equal "1" (treesit-node-text
+                            (treesit-search-subtree
+                             subarray "number"))))
+        ;; Find named node backward.
+        (should (equal "3" (treesit-node-text
+                            (treesit-search-subtree
+                             subarray "number" t))))
+        ;; Find anonymous node forward.
+        (should (equal "[" (treesit-node-text
+                            (treesit-search-subtree
+                             subarray "\\[" nil t))))
+        ;; Find anonymous node backward.
+        (should (equal "]" (treesit-node-text
+                            (treesit-search-subtree
+                             subarray "\\]" t t))))
+        ;; If ALL=nil, it shouldn't find anonymous node.
+        (should (eq nil (treesit-node-text
+                         (treesit-search-subtree
+                          subarray "\\["))))
+        ;; If ALL=nil, searching for number should still find the
+        ;; numbers.
+        (should (equal "1" (treesit-node-text
+                            (treesit-search-subtree
+                             subarray "number" nil t))))
+        ;; Find named node backward.
+        (should (equal "3" (treesit-node-text
+                            (treesit-search-subtree
+                             subarray "number" t t))))
+        ))))
+
+(defmacro treesit--ert-search-setup (&rest body)
+  "Setup macro used by `treesit-search-forward' and friends.
+BODY is the test body."
+  `(with-temp-buffer
+     (let (parser root array)
+       (progn
+         (insert "[[1,2,3], [4,5,6], [7,8,9]]")
+         (setq parser (treesit-parser-create 'json))
+         (setq root (treesit-parser-root-node
+                     parser))
+         (setq array (treesit-node-child root 0))
+         ;; First bracket.
+         (setq cursor (treesit-node-child array 0)))
+       ,@body)))
+
+(ert-deftest treesit-search-forward ()
+  "Test `treesit-search-forward'."
+  (skip-unless (treesit-language-available-p 'json))
+  (treesit--ert-search-setup
+   (cl-loop for cursor = (treesit-node-child array 0)
+            then (treesit-search-forward cursor "" nil t)
+            for text in '("[" "[" "1" "," "2" "," "3" "]"
+                          "[1,2,3]" ","
+                          "[" "4" "," "5" "," "6" "]"
+                          "[4,5,6]" ","
+                          "[" "7" "," "8" "," "9" "]"
+                          "[7,8,9]" "]"
+                          "[[1,2,3], [4,5,6], [7,8,9]]")
+            while cursor
+            do (should (equal (treesit-node-text cursor)
+                              text)))))
+
+(ert-deftest treesit-search-forward-named-only ()
+  "Test `treesit-search-forward'."
+  (skip-unless (treesit-language-available-p 'json))
+  (treesit--ert-search-setup
+   (cl-loop for cursor = (treesit-node-child
+                          (treesit-node-child array 1) 1)
+            then (treesit-search-forward cursor "")
+            for text in '("1" "2"  "3" "[1,2,3]"
+                          "4" "5" "6" "[4,5,6]"
+                          "7" "8"  "9" "[7,8,9]"
+                          "[[1,2,3], [4,5,6], [7,8,9]]")
+            while cursor
+            do (should (equal (treesit-node-text cursor)
+                              text)))))
+
+(ert-deftest treesit-search-backward ()
+  "Test `treesit-search-forward'."
+  (skip-unless (treesit-language-available-p 'json))
+  (treesit--ert-search-setup
+   (cl-loop for cursor = (treesit-node-child array -1)
+            then (treesit-search-forward cursor "" t t)
+            for text in (reverse '("[[1,2,3], [4,5,6], [7,8,9]]"
+                                   "[" "[1,2,3]"
+                                   "[" "1" "," "2" "," "3" "]"
+                                   "," "[4,5,6]"
+                                   "[" "4" "," "5" "," "6" "]"
+                                   "," "[7,8,9]"
+                                   "[" "7" "," "8" "," "9" "]"
+                                   "]"))
+            while cursor
+            do (should (equal (treesit-node-text cursor)
+                              text)))))
+
+(ert-deftest treesit-search-backward-named-only ()
+  "Test `treesit-search-forward'."
+  (skip-unless (treesit-language-available-p 'json))
+  (treesit--ert-search-setup
+   (cl-loop for cursor = (treesit-node-child
+                          (treesit-node-child array -1 t) -1 t)
+            then (treesit-search-forward cursor "" t)
+            for text in (reverse '("[[1,2,3], [4,5,6], [7,8,9]]"
+                                   "[1,2,3]" "1" "2"  "3"
+                                   "[4,5,6]" "4" "5" "6"
+                                   "[7,8,9]" "7" "8"  "9"))
+            while cursor
+            do (should (equal (treesit-node-text cursor)
+                              text)))))
+
+(ert-deftest treesit-cursor-helper-with-missing-node ()
+  "Test treesit_cursor_helper with a missing node."
+  (skip-unless (treesit-language-available-p 'json))
+  (treesit--ert-search-setup
+   (delete-char -1)
+   (setq root (treesit-buffer-root-node))
+   (setq array (treesit-node-child root 0))
+   ;; If everything works, this should not hang.
+   (let ((missing-bracket (treesit-node-child array -1)))
+     (treesit-search-forward missing-bracket "" t))))
+
+;;; Query
+
 (ert-deftest treesit-query-api ()
   "Tests for query API."
   (skip-unless (treesit-language-available-p 'json))
@@ -167,6 +346,9 @@
         (setq root-node (treesit-parser-root-node
                          parser)))
 
+      (should-error (treesit-query-capture root-node "" 100 101)
+                    :type 'args-out-of-range)
+
       ;; Test `treesit-query-capture' on string, sexp and compiled
       ;; queries.
       (dolist (query1
@@ -207,6 +389,8 @@
          '((type field: (_) @capture :anchor)
            :? :* :+ "return")))))))
 
+;;; Narrow
+
 (ert-deftest treesit-narrow ()
   "Tests if narrowing works."
   (skip-unless (treesit-language-available-p 'json))
@@ -343,6 +527,8 @@ visible_end.)"
       ;; that calls that.
       )))
 
+;;; Range
+
 (ert-deftest treesit-range ()
   "Tests if range works."
   (skip-unless (treesit-language-available-p 'json))
@@ -396,6 +582,8 @@ visible_end.)"
       ;; TODO: More tests.
       )))
 
+;;; Multiple language
+
 (ert-deftest treesit-multi-lang ()
   "Tests if parsing multiple language works."
   (skip-unless (and (treesit-language-available-p 'html)
@@ -432,6 +620,8 @@ visible_end.)"
       ;; TODO: More tests.
       )))
 
+;;; Supplemental functions
+
 (ert-deftest treesit-parser-supplemental ()
   "Supplemental node functions."
   (skip-unless (treesit-language-available-p 'json))
@@ -552,6 +742,288 @@ visible_end.)"
     (insert "]")
     (should (treesit-node-check array-node 'outdated))))
 
+;;; Defun navigation
+;;
+;; I've setup a framework for easier testing of defun navigation.
+;;
+;; To use it for a particular language, first write a test program
+;; similar to `treesit--ert-defun-navigation-python-program', and
+;; insert markers.  Markers that marks BOLs are defined as follows:
+;;
+;; 100 Before 1st parent
+;; 101 Beg of 1st parent
+;; 102 End of 1st parent
+;; 103 Beg of 2nd parent
+;; 104 Beg of 1st method
+;; 105 End of 1st method
+;; 106 Beg of 2nd method
+;; 107 End of 2nd method
+;; 108 End of 2nd parent
+;; 109 Beg of 3rd parent
+;; 110 End of 3rd parent
+;; 999 Dummy markers
+;;
+;; Then add marker 0-9 following the definition given in
+;; `treesit--ert-defun-navigation-nested-master'.  Then you can use
+;; `treesit--ert-test-defun-navigation', pass the test program you
+;; just wrote, and the appropriate master:
+;;
+;; - `treesit--ert-defun-navigation-nested-master' for nested defun
+;; - `treesit--ert-defun-navigation-top-level-master' for top-level
+
+
+(defun treesit--ert-insert-and-parse-marker (opening closing text)
+  "Insert TEXT and parse the marker positions in it.
+
+TEXT should be a string in which contains position markings
+like (1).  OPENING and CLOSING are position marking's delimiters,
+for (1), OPENING and CLOSING should be \"(\" and \")\",
+respectively.
+
+This function inserts TEXT, parses and removes all the markings,
+and returns an alist of (NUMBER . POS), where number is each
+marking's number, and POS is each marking's position."
+  (declare (indent 2))
+  (let (result)
+    (insert text)
+    (goto-char (point-min))
+    (while (re-search-forward
+            (rx-to-string `(seq ,opening (group (+ digit)) ,closing))
+            nil t)
+      (let ((idx (string-to-number (match-string 1))))
+        (push (cons idx (match-beginning 0)) result)
+        (delete-region (match-beginning 0) (match-end 0))))
+    (nreverse result)))
+
+(defun treesit--ert-collect-positions (positions functions)
+  "Collect positions after calling each function in FUNCTIONS.
+
+POSITIONS should be a list of buffer positions, FUNCTIONS should
+be a list of functions.  This function collects the return value
+of each function in FUNCTIONS starting at each position in
+POSITIONS.
+
+Return a list of (POS...) where each POS corresponds to a
+function in FUNCTIONS.  For example, if buffer content is
+\"123\", POSITIONS is (2 3), FUNCTIONS is (point-min point-max),
+the return value is ((1 3) (1 3))."
+  (cl-loop for pos in positions
+           collect (cl-loop for fn in functions
+                            collect (progn
+                                      (goto-char pos)
+                                      (funcall fn)))))
+
+(defun treesit--ert-test-defun-navigation
+    (init program master &optional opening closing)
+  "Run defun navigation tests on PROGRAM and MASTER.
+
+INIT is a setup function that runs right after this function
+creates a temporary buffer.  It should take no argument.
+
+PROGRAM is a program source in string, MASTER is a list of
+\(START PREV-BEG NEXT-END PREV-END NEXT-BEG), where START is the
+starting marker position, and the rest are marker positions the
+corresponding navigation should stop at (after running
+`treesit-defun-skipper').
+
+OPENING and CLOSING are the same as in
+`treesit--ert-insert-and-parse-marker', by default they are \"[\"
+and \"]\"."
+  (with-temp-buffer
+    (funcall init)
+    (let* ((opening (or opening "["))
+           (closing (or closing "]"))
+           ;; Insert program and parse marker positions.
+           (marker-alist (treesit--ert-insert-and-parse-marker
+                             opening closing program))
+           ;; Translate marker positions into buffer positions.
+           (decoded-master
+            (cl-loop for record in master
+                     collect
+                     (cl-loop for pos in record
+                              collect (alist-get pos marker-alist))))
+           ;; Collect positions each function returns.
+           (positions
+            (treesit--ert-collect-positions
+             ;; The first column of DECODED-MASTER.
+             (mapcar #'car decoded-master)
+             ;; Four functions: next-end, prev-beg, next-beg, prev-end.
+             (mapcar (lambda (conf)
+                       (lambda ()
+                         (if-let ((pos (funcall
+                                        #'treesit--navigate-defun
+                                        (point) (car conf) (cdr conf))))
+                             (save-excursion
+                               (goto-char pos)
+                               (funcall treesit-defun-skipper)
+                               (point)))))
+                     '((-1 . beg)
+                       (1 . end)
+                       (-1 . end)
+                       (1 . beg))))))
+      ;; Verify each position.
+      (cl-loop for record in decoded-master
+               for orig-record in master
+               for poss in positions
+               for name = (format "marker %d" (car orig-record))
+               do (should (equal (cons name (cdr record))
+                                 (cons name poss)))))))
+
+(defvar treesit--ert-defun-navigation-python-program
+  "[100]
+[101]class Class1():
+[999]    prop = 0
+[102]
+[103]class Class2():[0]
+[104]    [1]def method1():
+[999]        [2]return 0[3]
+[105]    [4]
+[106]    [5]def method2():
+[999]        [6]return 0[7]
+[107]    [8]
+[999]    prop = 0[9]
+[108]
+[109]class Class3():
+[999]    prop = 0[10]
+[110]
+"
+  "Python source for navigation test.")
+
+(defvar treesit--ert-defun-navigation-js-program
+  "[100]
+[101]class Class1 {
+[999]}
+[102]
+[103]class Class2 {[0]
+[104]  [1]method1() {
+[999]    [2]return 0;
+[999]  }[3]
+[105]  [4]
+[106]  [5]method2() {
+[999]    [6]return 0;
+[999]  }[7]
+[107][8]
+[999]}[9]
+[108]
+[109]class class3 {
+[999]}[10]
+[110]
+"
+  "Javascript source for navigation test.")
+
+(defvar treesit--ert-defun-navigation-bash-program
+  "[100]
+[101]parent1 () {
+[999]}
+[102]
+[103]parent2 () {[0]
+[104]    [1]sibling1 () {
+[999]        [2]echo hi
+[999]    }[3]
+[105]    [4]
+[106]    [5]sibling2 () {
+[999]        [6]echo hi
+[999]    }[7]
+[107][8]
+[999]}[9]
+[108]
+[109]parent3 () {
+[999]}
+[110]
+"
+  "Javascript source for navigation test.")
+
+(defvar treesit--ert-defun-navigation-nested-master
+  ;; START PREV-BEG NEXT-END PREV-END NEXT-BEG
+  '((0 103 105 102 106) ; Between Beg of parent & 1st sibling.
+    (1 103 105 102 106) ; Beg of 1st sibling.
+    (2 104 105 102 106) ; Inside 1st sibling.
+    (3 104 107 102 109) ; End of 1st sibling.
+    (4 104 107 102 109) ; Between 1st sibling & 2nd sibling.
+    (5 104 107 102 109) ; Beg of 2nd sibling.
+    (6 106 107 105 109) ; Inside 2nd sibling.
+    (7 106 108 105 109) ; End of 2nd sibling.
+    (8 106 108 105 109) ; Between 2nd sibling & end of parent.
+    (9 103 110 102 nil) ; End of parent.
+
+    (100 nil 102 nil 103) ; Before 1st parent.
+    (101 nil 102 nil 103) ; Beg of 1st parent.
+    (102 101 108 nil 109) ; Between 1st & 2nd parent.
+    (103 101 108 nil 109) ; Beg of 2nd parent.
+    (110 109 nil 108 nil) ; After 3rd parent.
+    )
+  "Master of nested navigation test.
+
+This basically says, e.g., \"start with point on marker 0, go to
+the prev-beg, now point should be at marker 103\", etc.")
+
+(defvar treesit--ert-defun-navigation-top-level-master
+  ;; START PREV-BEG NEXT-END NEXT-BEG PREV-END
+  '((0 103 108 102 109) ; Between Beg of parent & 1st sibling.
+    (1 103 108 102 109) ; Beg of 1st sibling.
+    (2 103 108 102 109) ; Inside 1st sibling.
+    (3 103 108 102 109) ; End of 1st sibling.
+    (4 103 108 102 109) ; Between 1st sibling & 2nd sibling.
+    (5 103 108 102 109) ; Beg of 2nd sibling.
+    (6 103 108 102 109) ; Inside 2nd sibling.
+    (7 103 108 102 109) ; End of 2nd sibling.
+    (8 103 108 102 109) ; Between 2nd sibling & end of parent.
+    (9 103 110 102 nil) ; End of parent.
+
+    ;; Top-level defuns should be identical to the nested test.
+    (100 nil 102 nil 103) ; Before 1st parent.
+    (101 nil 102 nil 103) ; Beg of 1st parent.
+    (102 101 108 nil 109) ; Between 1st & 2nd parent.
+    (103 101 108 nil 109) ; Beg of 2nd parent.
+    (110 109 nil 108 nil) ; After 3rd parent.
+    )
+  "Master of top-level navigation test.")
+
+(ert-deftest treesit-defun-navigation-nested-1 ()
+  "Test defun navigation."
+  (skip-unless (treesit-language-available-p 'python))
+  ;; Nested defun navigation
+  (let ((treesit-defun-tactic 'nested))
+    (require 'python)
+    (treesit--ert-test-defun-navigation
+     'python-ts-mode
+     treesit--ert-defun-navigation-python-program
+     treesit--ert-defun-navigation-nested-master)))
+
+(ert-deftest treesit-defun-navigation-nested-2 ()
+  "Test defun navigation using `js-ts-mode'."
+  (skip-unless (treesit-language-available-p 'javascript))
+  ;; Nested defun navigation
+  (let ((treesit-defun-tactic 'nested))
+    (require 'js)
+    (treesit--ert-test-defun-navigation
+     'js-ts-mode
+     treesit--ert-defun-navigation-js-program
+     treesit--ert-defun-navigation-nested-master)))
+
+(ert-deftest treesit-defun-navigation-nested-3 ()
+  "Test defun navigation using `bash-ts-mode'."
+  (skip-unless (treesit-language-available-p 'bash))
+  ;; Nested defun navigation
+  (let ((treesit-defun-tactic 'nested))
+    (treesit--ert-test-defun-navigation
+     (lambda ()
+       (treesit-parser-create 'bash)
+       (setq-local treesit-defun-type-regexp "function_definition"))
+     treesit--ert-defun-navigation-bash-program
+     treesit--ert-defun-navigation-nested-master)))
+
+(ert-deftest treesit-defun-navigation-top-level ()
+  "Test top-level only defun navigation."
+  (skip-unless (treesit-language-available-p 'python))
+  ;; Nested defun navigation
+  (let ((treesit-defun-tactic 'top-level))
+    (require 'python)
+    (treesit--ert-test-defun-navigation
+     'python-ts-mode
+     treesit--ert-defun-navigation-python-program
+     treesit--ert-defun-navigation-top-level-master)))
+
 ;; TODO
 ;; - Functions in treesit.el
 ;; - treesit-load-name-override-list



reply via email to

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